Repository: codama-idl/codama Branch: main Commit: 394e9b6afb6e Files: 1211 Total size: 4.4 MB Directory structure: gitextract_ki3ckuuc/ ├── .changeset/ │ ├── README.md │ └── config.json ├── .github/ │ ├── actions/ │ │ └── setup-anchor/ │ │ └── action.yml │ ├── dependabot.yml │ └── workflows/ │ └── main.yml ├── .gitignore ├── .prettierignore ├── LICENSE ├── README.md ├── eslint.config.mjs ├── package.json ├── packages/ │ ├── cli/ │ │ ├── .gitignore │ │ ├── .prettierignore │ │ ├── LICENSE │ │ ├── README.md │ │ ├── bin/ │ │ │ └── cli.cjs │ │ ├── package.json │ │ ├── src/ │ │ │ ├── cli/ │ │ │ │ └── index.ts │ │ │ ├── commands/ │ │ │ │ ├── convert.ts │ │ │ │ ├── index.ts │ │ │ │ ├── init.ts │ │ │ │ └── run.ts │ │ │ ├── config.ts │ │ │ ├── index.ts │ │ │ ├── parsedConfig.ts │ │ │ ├── program.ts │ │ │ ├── programOptions.ts │ │ │ ├── types/ │ │ │ │ └── global.d.ts │ │ │ └── utils/ │ │ │ ├── childCommands.ts │ │ │ ├── errors.ts │ │ │ ├── fs.ts │ │ │ ├── import.ts │ │ │ ├── index.ts │ │ │ ├── logs.ts │ │ │ ├── nodes.ts │ │ │ ├── packageInstall.ts │ │ │ ├── packageJson.ts │ │ │ ├── packageManager.ts │ │ │ ├── promises.ts │ │ │ ├── prompts.ts │ │ │ └── visitors.ts │ │ ├── test/ │ │ │ ├── exports/ │ │ │ │ ├── commonjs.cjs │ │ │ │ ├── mock-config.json │ │ │ │ ├── mock-idl.json │ │ │ │ └── module.mjs │ │ │ └── index.test.ts │ │ ├── tsconfig.declarations.json │ │ ├── tsconfig.json │ │ ├── tsup.config.ts │ │ └── vitest.config.mts │ ├── dynamic-client/ │ │ ├── .gitignore │ │ ├── .prettierignore │ │ ├── LICENSE │ │ ├── README.md │ │ ├── bin/ │ │ │ └── cli.cjs │ │ ├── package.json │ │ ├── scripts/ │ │ │ └── generate-idl-from-anchor.mjs │ │ ├── src/ │ │ │ ├── cli/ │ │ │ │ ├── commands/ │ │ │ │ │ ├── generate-client-types/ │ │ │ │ │ │ ├── generate-client-types-from-file.ts │ │ │ │ │ │ ├── generate-client-types.ts │ │ │ │ │ │ └── register-command.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ └── program.ts │ │ │ ├── index.ts │ │ │ ├── instruction-encoding/ │ │ │ │ ├── accounts/ │ │ │ │ │ ├── create-account-meta.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── validate-accounts-input.ts │ │ │ │ ├── arguments/ │ │ │ │ │ ├── encode-instruction-arguments.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── resolve-argument-from-custom-resolvers.ts │ │ │ │ │ ├── shared.ts │ │ │ │ │ └── validate-arguments-input.ts │ │ │ │ ├── index.ts │ │ │ │ ├── instructions.ts │ │ │ │ ├── resolvers/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── resolve-account-address.ts │ │ │ │ │ ├── resolve-account-value-node-address.ts │ │ │ │ │ ├── resolve-conditional.ts │ │ │ │ │ ├── resolve-pda-address.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── validators.ts │ │ │ │ └── visitors/ │ │ │ │ ├── account-default-value.ts │ │ │ │ ├── condition-node-value.ts │ │ │ │ ├── default-value-encoder.ts │ │ │ │ ├── index.ts │ │ │ │ ├── input-value-transformer.ts │ │ │ │ ├── pda-seed-value.ts │ │ │ │ └── value-node-value.ts │ │ │ ├── program-client/ │ │ │ │ ├── collect-pdas.ts │ │ │ │ ├── create-program-client.ts │ │ │ │ ├── derive-standalone-pda.ts │ │ │ │ └── methods-builder.ts │ │ │ ├── shared/ │ │ │ │ ├── address.ts │ │ │ │ ├── bytes-encoding.ts │ │ │ │ ├── codecs.ts │ │ │ │ ├── nodes.ts │ │ │ │ ├── types.ts │ │ │ │ └── util.ts │ │ │ └── types/ │ │ │ └── index.ts │ │ ├── test/ │ │ │ ├── programs/ │ │ │ │ ├── anchor/ │ │ │ │ │ ├── Anchor.toml │ │ │ │ │ ├── Cargo.toml │ │ │ │ │ ├── programs/ │ │ │ │ │ │ ├── blog/ │ │ │ │ │ │ │ ├── Cargo.toml │ │ │ │ │ │ │ ├── Xargo.toml │ │ │ │ │ │ │ └── src/ │ │ │ │ │ │ │ └── lib.rs │ │ │ │ │ │ └── example/ │ │ │ │ │ │ ├── Cargo.toml │ │ │ │ │ │ ├── Xargo.toml │ │ │ │ │ │ └── src/ │ │ │ │ │ │ ├── lib.rs │ │ │ │ │ │ └── nested_example.rs │ │ │ │ │ ├── rust-toolchain.toml │ │ │ │ │ └── tests/ │ │ │ │ │ ├── blog.test.ts │ │ │ │ │ ├── example.test.ts │ │ │ │ │ ├── helpers.ts │ │ │ │ │ └── nested-example-ix.test.ts │ │ │ │ ├── associated-token-account/ │ │ │ │ │ ├── ata-test-utils.ts │ │ │ │ │ ├── create-idempotent.test.ts │ │ │ │ │ ├── create.test.ts │ │ │ │ │ └── recover-nested.test.ts │ │ │ │ ├── circular-account-refs/ │ │ │ │ │ └── circular-account-refs.test.ts │ │ │ │ ├── collection-types/ │ │ │ │ │ └── collection-types.test.ts │ │ │ │ ├── custom-resolvers/ │ │ │ │ │ ├── account-resolver.test.ts │ │ │ │ │ ├── argument-resolvers.test.ts │ │ │ │ │ └── custom-resolvers-test-utils.ts │ │ │ │ ├── idls/ │ │ │ │ │ ├── associated-token-account-idl.json │ │ │ │ │ ├── blog-idl.json │ │ │ │ │ ├── circular-account-refs-idl.json │ │ │ │ │ ├── collection-types-idl.json │ │ │ │ │ ├── custom-resolvers-test-idl.json │ │ │ │ │ ├── example-idl.json │ │ │ │ │ ├── mpl-token-metadata-idl.json │ │ │ │ │ ├── pmp-idl.json │ │ │ │ │ ├── sas-idl.json │ │ │ │ │ ├── system-program-idl.json │ │ │ │ │ ├── token-2022-idl.json │ │ │ │ │ └── token-idl.json │ │ │ │ ├── mpl-token-metadata/ │ │ │ │ │ ├── create-with-resolvers.test.ts │ │ │ │ │ ├── create.test.ts │ │ │ │ │ └── helpers.ts │ │ │ │ ├── pmp/ │ │ │ │ │ ├── allocate.test.ts │ │ │ │ │ ├── close.test.ts │ │ │ │ │ ├── extend.test.ts │ │ │ │ │ ├── helpers.ts │ │ │ │ │ ├── initialize.test.ts │ │ │ │ │ ├── pdas.test.ts │ │ │ │ │ ├── set-authority.test.ts │ │ │ │ │ ├── set-data.test.ts │ │ │ │ │ ├── set-immutable.test.ts │ │ │ │ │ ├── trim.test.ts │ │ │ │ │ └── write.test.ts │ │ │ │ ├── sas/ │ │ │ │ │ ├── change-authorized-signers.test.ts │ │ │ │ │ ├── change-schema-description.test.ts │ │ │ │ │ ├── change-schema-status.test.ts │ │ │ │ │ ├── change-schema-version.test.ts │ │ │ │ │ ├── close-attestation.test.ts │ │ │ │ │ ├── close-tokenized-attestation.test.ts │ │ │ │ │ ├── create-attestation.test.ts │ │ │ │ │ ├── create-credential.test.ts │ │ │ │ │ ├── create-schema.test.ts │ │ │ │ │ ├── create-tokenized-attestation.test.ts │ │ │ │ │ ├── sas-test-utils.ts │ │ │ │ │ └── tokenize-schema.test.ts │ │ │ │ ├── system-program/ │ │ │ │ │ ├── advance-nonce-account.test.ts │ │ │ │ │ ├── allocate-with-seed.test.ts │ │ │ │ │ ├── allocate.test.ts │ │ │ │ │ ├── assign-with-seed.test.ts │ │ │ │ │ ├── assign.test.ts │ │ │ │ │ ├── authorize-nonce-account.test.ts │ │ │ │ │ ├── create-account-with-seed.test.ts │ │ │ │ │ ├── create-account.test.ts │ │ │ │ │ ├── initialize-nonce-account.test.ts │ │ │ │ │ ├── transfer-sol-with-seed.test.ts │ │ │ │ │ ├── transfer-sol.test.ts │ │ │ │ │ ├── upgrade-nonce-account.test.ts │ │ │ │ │ └── withdraw-nonce-account.test.ts │ │ │ │ ├── test-utils.ts │ │ │ │ ├── token/ │ │ │ │ │ ├── amount-to-ui-amount.test.ts │ │ │ │ │ ├── approve-checked.test.ts │ │ │ │ │ ├── approve.test.ts │ │ │ │ │ ├── burn-checked.test.ts │ │ │ │ │ ├── burn.test.ts │ │ │ │ │ ├── close-account.test.ts │ │ │ │ │ ├── freeze-account.test.ts │ │ │ │ │ ├── get-account-data-size.test.ts │ │ │ │ │ ├── initialize-account.test.ts │ │ │ │ │ ├── initialize-account2.test.ts │ │ │ │ │ ├── initialize-account3.test.ts │ │ │ │ │ ├── initialize-immutable-owner.test.ts │ │ │ │ │ ├── initialize-mint.test.ts │ │ │ │ │ ├── initialize-mint2.test.ts │ │ │ │ │ ├── initialize-multisig.test.ts │ │ │ │ │ ├── initialize-multisig2.test.ts │ │ │ │ │ ├── mint-to-checked.test.ts │ │ │ │ │ ├── mint-to.test.ts │ │ │ │ │ ├── revoke.test.ts │ │ │ │ │ ├── set-authority.test.ts │ │ │ │ │ ├── sync-native.test.ts │ │ │ │ │ ├── thaw-account.test.ts │ │ │ │ │ ├── token-test-utils.ts │ │ │ │ │ ├── transfer-checked.test.ts │ │ │ │ │ ├── transfer.test.ts │ │ │ │ │ └── ui-amount-to-amount.test.ts │ │ │ │ └── token-2022/ │ │ │ │ ├── amount-to-ui-amount.test.ts │ │ │ │ ├── approve-checked.test.ts │ │ │ │ ├── approve.test.ts │ │ │ │ ├── burn-checked.test.ts │ │ │ │ ├── burn.test.ts │ │ │ │ ├── close-account.test.ts │ │ │ │ ├── confidential-transfer-fee.test.ts │ │ │ │ ├── confidential-transfer.test.ts │ │ │ │ ├── create-native-mint.test.ts │ │ │ │ ├── disable-cpi-guard.test.ts │ │ │ │ ├── disable-memo-transfers.test.ts │ │ │ │ ├── freeze-account.test.ts │ │ │ │ ├── get-account-data-size.test.ts │ │ │ │ ├── group-member-pointer.test.ts │ │ │ │ ├── group-pointer.test.ts │ │ │ │ ├── harvest-withheld-tokens-to-mint.test.ts │ │ │ │ ├── initialize-account.test.ts │ │ │ │ ├── initialize-account2.test.ts │ │ │ │ ├── initialize-account3.test.ts │ │ │ │ ├── initialize-default-account-state.test.ts │ │ │ │ ├── initialize-immutable-owner.test.ts │ │ │ │ ├── initialize-interest-bearing-mint.test.ts │ │ │ │ ├── initialize-mint-close-authority.test.ts │ │ │ │ ├── initialize-mint.test.ts │ │ │ │ ├── initialize-mint2.test.ts │ │ │ │ ├── initialize-multisig.test.ts │ │ │ │ ├── initialize-multisig2.test.ts │ │ │ │ ├── initialize-non-transferable-mint.test.ts │ │ │ │ ├── initialize-permanent-delegate.test.ts │ │ │ │ ├── metadata-pointer.test.ts │ │ │ │ ├── mint-to-checked.test.ts │ │ │ │ ├── mint-to.test.ts │ │ │ │ ├── pausable.test.ts │ │ │ │ ├── reallocate.test.ts │ │ │ │ ├── revoke.test.ts │ │ │ │ ├── scaled-ui-amount.test.ts │ │ │ │ ├── set-authority.test.ts │ │ │ │ ├── sync-native.test.ts │ │ │ │ ├── thaw-account.test.ts │ │ │ │ ├── token-2022-test-utils.ts │ │ │ │ ├── token-group.test.ts │ │ │ │ ├── token-metadata.test.ts │ │ │ │ ├── transfer-checked.test.ts │ │ │ │ ├── transfer-fee.test.ts │ │ │ │ ├── transfer-hook.test.ts │ │ │ │ ├── transfer.test.ts │ │ │ │ ├── ui-amount-to-amount.test.ts │ │ │ │ ├── update-default-account-state.test.ts │ │ │ │ ├── update-rate-interest-bearing-mint.test.ts │ │ │ │ ├── withdraw-excess-lamports.test.ts │ │ │ │ └── withdraw-withheld-tokens.test.ts │ │ │ ├── svm-test-context.ts │ │ │ └── unit/ │ │ │ ├── cli/ │ │ │ │ ├── generate-program-client-types.test.ts │ │ │ │ └── program-client-types.test.ts │ │ │ ├── instruction-encoding/ │ │ │ │ ├── arguments.test.ts │ │ │ │ ├── create-account-meta.test.ts │ │ │ │ └── validators.test.ts │ │ │ ├── program-client/ │ │ │ │ └── create-program-client.test.ts │ │ │ ├── resolvers/ │ │ │ │ ├── resolve-account-value-node-address/ │ │ │ │ │ ├── resolve-account-value-node-address.test.ts │ │ │ │ │ └── types.test.ts │ │ │ │ └── resolve-conditional.test.ts │ │ │ ├── shared/ │ │ │ │ ├── address.test.ts │ │ │ │ ├── bytes-encoding.test.ts │ │ │ │ ├── codecs.test.ts │ │ │ │ ├── types.test.ts │ │ │ │ └── util.test.ts │ │ │ └── visitors/ │ │ │ ├── account-default-value/ │ │ │ │ ├── account-default-value-test-utils.ts │ │ │ │ ├── accountBumpValueNode.test.ts │ │ │ │ ├── accountValueNode.test.ts │ │ │ │ ├── argumentValueNode.test.ts │ │ │ │ ├── conditionalValueNode.test.ts │ │ │ │ ├── identityValueNode.test.ts │ │ │ │ ├── payerValueNode.test.ts │ │ │ │ ├── pdaValueNode.test.ts │ │ │ │ ├── programIdValueNode.test.ts │ │ │ │ ├── publicKeyValueNode.test.ts │ │ │ │ └── resolverValueNode.test.ts │ │ │ ├── condition-node-value/ │ │ │ │ ├── accountValueNode.test.ts │ │ │ │ ├── argumentValueNode.test.ts │ │ │ │ ├── condition-node-value-test-utils.ts │ │ │ │ └── resolverValueNode.test.ts │ │ │ ├── default-value-encoder/ │ │ │ │ ├── booleanValueNode.test.ts │ │ │ │ ├── bytesValueNode.test.ts │ │ │ │ ├── default-value-encoder-test-utils.ts │ │ │ │ ├── enumValueNode.test.ts │ │ │ │ ├── noneValueNode.test.ts │ │ │ │ ├── numberValueNode.test.ts │ │ │ │ ├── publicKeyValueNode.test.ts │ │ │ │ └── stringValueNode.test.ts │ │ │ ├── input-value-transformer/ │ │ │ │ ├── amountTypeNode.test.ts │ │ │ │ ├── arrayTypeNode.test.ts │ │ │ │ ├── booleanTypeNode.test.ts │ │ │ │ ├── bytesTypeNode.test.ts │ │ │ │ ├── dateTimeTypeNode.test.ts │ │ │ │ ├── definedTypeLinkNode.test.ts │ │ │ │ ├── enumTypeNode.test.ts │ │ │ │ ├── fixedSizeTypeNode.test.ts │ │ │ │ ├── hiddenPrefixTypeNode.test.ts │ │ │ │ ├── hiddenSuffixTypeNode.test.ts │ │ │ │ ├── input-value-transformer-test-utils.ts │ │ │ │ ├── mapTypeNode.test.ts │ │ │ │ ├── numberTypeNode.test.ts │ │ │ │ ├── optionTypeNode.test.ts │ │ │ │ ├── postOffsetTypeNode.test.ts │ │ │ │ ├── preOffsetTypeNode.test.ts │ │ │ │ ├── publicKeyTypeNode.test.ts │ │ │ │ ├── remainderOptionTypeNode.test.ts │ │ │ │ ├── sentinelTypeNode.test.ts │ │ │ │ ├── setTypeNode.test.ts │ │ │ │ ├── sizePrefixTypeNode.test.ts │ │ │ │ ├── solAmountTypeNode.test.ts │ │ │ │ ├── stringTypeNode.test.ts │ │ │ │ ├── structTypeNode.test.ts │ │ │ │ ├── tupleTypeNode.test.ts │ │ │ │ └── zeroableOptionTypeNode.test.ts │ │ │ ├── pda-seed-value/ │ │ │ │ ├── accountValueNode.test.ts │ │ │ │ ├── argumentValueNode.test.ts │ │ │ │ ├── booleanValueNode.test.ts │ │ │ │ ├── bytesValueNode.test.ts │ │ │ │ ├── constantValueNode.test.ts │ │ │ │ ├── noneValueNode.test.ts │ │ │ │ ├── numberValueNode.test.ts │ │ │ │ ├── pda-seed-value-test-utils.ts │ │ │ │ ├── programIdValueNode.test.ts │ │ │ │ ├── publicKeyValueNode.test.ts │ │ │ │ ├── someValueNode.test.ts │ │ │ │ └── stringValueNode.test.ts │ │ │ └── value-node-value/ │ │ │ ├── arrayValueNode.test.ts │ │ │ ├── booleanValueNode.test.ts │ │ │ ├── bytesValueNode.test.ts │ │ │ ├── constantValueNode.test.ts │ │ │ ├── enumValueNode.test.ts │ │ │ ├── mapValueNode.test.ts │ │ │ ├── noneValueNode.test.ts │ │ │ ├── numberValueNode.test.ts │ │ │ ├── publicKeyValueNode.test.ts │ │ │ ├── setValueNode.test.ts │ │ │ ├── someValueNode.test.ts │ │ │ ├── stringValueNode.test.ts │ │ │ ├── structValueNode.test.ts │ │ │ ├── tupleValueNode.test.ts │ │ │ └── value-node-value-test-utils.ts │ │ ├── tsconfig.declarations.json │ │ ├── tsconfig.json │ │ ├── tsup.cli.config.ts │ │ ├── tsup.config.ts │ │ └── vitest.config.mts │ ├── dynamic-codecs/ │ │ ├── .gitignore │ │ ├── .prettierignore │ │ ├── LICENSE │ │ ├── README.md │ │ ├── package.json │ │ ├── src/ │ │ │ ├── codecs.ts │ │ │ ├── index.ts │ │ │ ├── types/ │ │ │ │ └── global.d.ts │ │ │ └── values.ts │ │ ├── test/ │ │ │ ├── _setup.ts │ │ │ ├── codecs/ │ │ │ │ ├── AccountNode.test.ts │ │ │ │ ├── ArrayTypeNode.test.ts │ │ │ │ ├── BooleanTypeNode.test.ts │ │ │ │ ├── BytesTypeNode.test.ts │ │ │ │ ├── DefinedTypeLinkNode.test.ts │ │ │ │ ├── DefinedTypeNode.test.ts │ │ │ │ ├── EnumTypeNode.test.ts │ │ │ │ ├── EventNode.test.ts │ │ │ │ ├── FixedSizeTypeNode.test.ts │ │ │ │ ├── HiddenPrefixTypeNode.test.ts │ │ │ │ ├── HiddenSuffixTypeNode.test.ts │ │ │ │ ├── InstructionArgumentNode.test.ts │ │ │ │ ├── InstructionNode.test.ts │ │ │ │ ├── MapTypeNode.test.ts │ │ │ │ ├── NumberTypeNode.test.ts │ │ │ │ ├── OptionTypeNode.test.ts │ │ │ │ ├── PostOffsetTypeNode.test.ts │ │ │ │ ├── PreOffsetTypeNode.test.ts │ │ │ │ ├── PublicKeyTypeNode.test.ts │ │ │ │ ├── RemainderOptionTypeNode.test.ts │ │ │ │ ├── SentinelTypeNode.test.ts │ │ │ │ ├── SetTypeNode.test.ts │ │ │ │ ├── SizePrefixTypeNode.test.ts │ │ │ │ ├── StringTypeNode.test.ts │ │ │ │ ├── StructFieldTypeNode.test.ts │ │ │ │ ├── StructTypeNode.test.ts │ │ │ │ ├── TupleTypeNode.test.ts │ │ │ │ └── ZeroableOptionTypeNode.test.ts │ │ │ ├── types/ │ │ │ │ └── global.d.ts │ │ │ └── values/ │ │ │ ├── ArrayValueNode.test.ts │ │ │ ├── BytesValueNode.test.ts │ │ │ ├── ConstantValueNode.test.ts │ │ │ ├── EnumValueNode.test.ts │ │ │ ├── MapValueNode.test.ts │ │ │ ├── NoneValueNode.test.ts │ │ │ ├── NumberValueNode.test.ts │ │ │ ├── PublicKeyValueNode.test.ts │ │ │ ├── SetValueNode.test.ts │ │ │ ├── SomeValueNode.test.ts │ │ │ ├── StringValueNode.test.ts │ │ │ ├── StructValueNode.test.ts │ │ │ └── TupleValueNode.test.ts │ │ ├── tsconfig.declarations.json │ │ ├── tsconfig.json │ │ ├── tsup.config.ts │ │ └── vitest.config.mts │ ├── dynamic-parsers/ │ │ ├── .gitignore │ │ ├── .prettierignore │ │ ├── LICENSE │ │ ├── README.md │ │ ├── package.json │ │ ├── src/ │ │ │ ├── discriminators.ts │ │ │ ├── identify.ts │ │ │ ├── index.ts │ │ │ ├── parsers.ts │ │ │ └── types/ │ │ │ └── global.d.ts │ │ ├── test/ │ │ │ ├── _setup.ts │ │ │ ├── discriminators.test.ts │ │ │ ├── identify.test.ts │ │ │ ├── parsers.test.ts │ │ │ └── types/ │ │ │ └── global.d.ts │ │ ├── tsconfig.declarations.json │ │ ├── tsconfig.json │ │ ├── tsup.config.ts │ │ └── vitest.config.mts │ ├── errors/ │ │ ├── .gitignore │ │ ├── .prettierignore │ │ ├── LICENSE │ │ ├── README.md │ │ ├── bin/ │ │ │ └── cli.cjs │ │ ├── package.json │ │ ├── src/ │ │ │ ├── cli/ │ │ │ │ └── index.ts │ │ │ ├── codes.ts │ │ │ ├── context.ts │ │ │ ├── error.ts │ │ │ ├── index.ts │ │ │ ├── logs.ts │ │ │ ├── message-formatter.ts │ │ │ ├── messages.ts │ │ │ ├── stack-trace.ts │ │ │ └── types/ │ │ │ └── global.d.ts │ │ ├── test/ │ │ │ ├── error.test.ts │ │ │ ├── error.typetest.ts │ │ │ └── types/ │ │ │ └── global.d.ts │ │ ├── tsconfig.declarations.json │ │ ├── tsconfig.json │ │ ├── tsup.config.ts │ │ └── vitest.config.mts │ ├── library/ │ │ ├── .gitignore │ │ ├── .prettierignore │ │ ├── LICENSE │ │ ├── README.md │ │ ├── bin/ │ │ │ └── cli.cjs │ │ ├── package.json │ │ ├── src/ │ │ │ ├── cli/ │ │ │ │ └── index.ts │ │ │ ├── codama.ts │ │ │ ├── index.ts │ │ │ └── types/ │ │ │ └── global.d.ts │ │ ├── test/ │ │ │ └── index.test.ts │ │ ├── tsconfig.declarations.json │ │ ├── tsconfig.json │ │ ├── tsup.config.ts │ │ └── vitest.config.mts │ ├── node-types/ │ │ ├── .gitignore │ │ ├── .prettierignore │ │ ├── LICENSE │ │ ├── README.md │ │ ├── package.json │ │ ├── src/ │ │ │ ├── AccountNode.ts │ │ │ ├── DefinedTypeNode.ts │ │ │ ├── ErrorNode.ts │ │ │ ├── EventNode.ts │ │ │ ├── InstructionAccountNode.ts │ │ │ ├── InstructionArgumentNode.ts │ │ │ ├── InstructionByteDeltaNode.ts │ │ │ ├── InstructionNode.ts │ │ │ ├── InstructionRemainingAccountsNode.ts │ │ │ ├── InstructionStatusNode.ts │ │ │ ├── Node.ts │ │ │ ├── PdaNode.ts │ │ │ ├── ProgramNode.ts │ │ │ ├── RootNode.ts │ │ │ ├── contextualValueNodes/ │ │ │ │ ├── AccountBumpValueNode.ts │ │ │ │ ├── AccountValueNode.ts │ │ │ │ ├── ArgumentValueNode.ts │ │ │ │ ├── ConditionalValueNode.ts │ │ │ │ ├── ContextualValueNode.ts │ │ │ │ ├── IdentityValueNode.ts │ │ │ │ ├── PayerValueNode.ts │ │ │ │ ├── PdaSeedValueNode.ts │ │ │ │ ├── PdaValueNode.ts │ │ │ │ ├── ProgramIdValueNode.ts │ │ │ │ ├── ResolverValueNode.ts │ │ │ │ └── index.ts │ │ │ ├── countNodes/ │ │ │ │ ├── CountNode.ts │ │ │ │ ├── FixedCountNode.ts │ │ │ │ ├── PrefixedCountNode.ts │ │ │ │ ├── RemainderCountNode.ts │ │ │ │ └── index.ts │ │ │ ├── discriminatorNodes/ │ │ │ │ ├── ConstantDiscriminatorNode.ts │ │ │ │ ├── DiscriminatorNode.ts │ │ │ │ ├── FieldDiscriminatorNode.ts │ │ │ │ ├── SizeDiscriminatorNode.ts │ │ │ │ └── index.ts │ │ │ ├── index.ts │ │ │ ├── linkNodes/ │ │ │ │ ├── AccountLinkNode.ts │ │ │ │ ├── DefinedTypeLinkNode.ts │ │ │ │ ├── InstructionAccountLinkNode.ts │ │ │ │ ├── InstructionArgumentLinkNode.ts │ │ │ │ ├── InstructionLinkNode.ts │ │ │ │ ├── LinkNode.ts │ │ │ │ ├── PdaLinkNode.ts │ │ │ │ ├── ProgramLinkNode.ts │ │ │ │ └── index.ts │ │ │ ├── pdaSeedNodes/ │ │ │ │ ├── ConstantPdaSeedNode.ts │ │ │ │ ├── PdaSeedNode.ts │ │ │ │ ├── VariablePdaSeedNode.ts │ │ │ │ └── index.ts │ │ │ ├── shared/ │ │ │ │ ├── bytesEncoding.ts │ │ │ │ ├── docs.ts │ │ │ │ ├── index.ts │ │ │ │ ├── instructionLifecycle.ts │ │ │ │ ├── stringCases.ts │ │ │ │ └── version.ts │ │ │ ├── typeNodes/ │ │ │ │ ├── AmountTypeNode.ts │ │ │ │ ├── ArrayTypeNode.ts │ │ │ │ ├── BooleanTypeNode.ts │ │ │ │ ├── BytesTypeNode.ts │ │ │ │ ├── DateTimeTypeNode.ts │ │ │ │ ├── EnumEmptyVariantTypeNode.ts │ │ │ │ ├── EnumStructVariantTypeNode.ts │ │ │ │ ├── EnumTupleVariantTypeNode.ts │ │ │ │ ├── EnumTypeNode.ts │ │ │ │ ├── EnumVariantTypeNode.ts │ │ │ │ ├── FixedSizeTypeNode.ts │ │ │ │ ├── HiddenPrefixTypeNode.ts │ │ │ │ ├── HiddenSuffixTypeNode.ts │ │ │ │ ├── MapTypeNode.ts │ │ │ │ ├── NestedTypeNode.ts │ │ │ │ ├── NumberTypeNode.ts │ │ │ │ ├── OptionTypeNode.ts │ │ │ │ ├── PostOffsetTypeNode.ts │ │ │ │ ├── PreOffsetTypeNode.ts │ │ │ │ ├── PublicKeyTypeNode.ts │ │ │ │ ├── RemainderOptionTypeNode.ts │ │ │ │ ├── SentinelTypeNode.ts │ │ │ │ ├── SetTypeNode.ts │ │ │ │ ├── SizePrefixTypeNode.ts │ │ │ │ ├── SolAmountTypeNode.ts │ │ │ │ ├── StringTypeNode.ts │ │ │ │ ├── StructFieldTypeNode.ts │ │ │ │ ├── StructTypeNode.ts │ │ │ │ ├── TupleTypeNode.ts │ │ │ │ ├── TypeNode.ts │ │ │ │ ├── ZeroableOptionTypeNode.ts │ │ │ │ └── index.ts │ │ │ └── valueNodes/ │ │ │ ├── ArrayValueNode.ts │ │ │ ├── BooleanValueNode.ts │ │ │ ├── BytesValueNode.ts │ │ │ ├── ConstantValueNode.ts │ │ │ ├── EnumValueNode.ts │ │ │ ├── MapEntryValueNode.ts │ │ │ ├── MapValueNode.ts │ │ │ ├── NoneValueNode.ts │ │ │ ├── NumberValueNode.ts │ │ │ ├── PublicKeyValueNode.ts │ │ │ ├── SetValueNode.ts │ │ │ ├── SomeValueNode.ts │ │ │ ├── StringValueNode.ts │ │ │ ├── StructFieldValueNode.ts │ │ │ ├── StructValueNode.ts │ │ │ ├── TupleValueNode.ts │ │ │ ├── ValueNode.ts │ │ │ └── index.ts │ │ ├── test/ │ │ │ └── GetNodeFromKind.typetest.ts │ │ ├── tsconfig.declarations.json │ │ ├── tsconfig.json │ │ └── tsup.config.ts │ ├── nodes/ │ │ ├── .gitignore │ │ ├── .prettierignore │ │ ├── LICENSE │ │ ├── README.md │ │ ├── docs/ │ │ │ ├── AccountNode.md │ │ │ ├── DefinedTypeNode.md │ │ │ ├── ErrorNode.md │ │ │ ├── EventNode.md │ │ │ ├── InstructionAccountNode.md │ │ │ ├── InstructionArgumentNode.md │ │ │ ├── InstructionByteDeltaNode.md │ │ │ ├── InstructionNode.md │ │ │ ├── InstructionRemainingAccountsNode.md │ │ │ ├── InstructionStatusNode.md │ │ │ ├── PdaNode.md │ │ │ ├── ProgramNode.md │ │ │ ├── README.md │ │ │ ├── RootNode.md │ │ │ ├── _template.md │ │ │ ├── contextualValueNodes/ │ │ │ │ ├── AccountBumpValueNode.md │ │ │ │ ├── AccountValueNode.md │ │ │ │ ├── ArgumentValueNode.md │ │ │ │ ├── ConditionalValueNode.md │ │ │ │ ├── IdentityValueNode.md │ │ │ │ ├── InstructionInputValueNode.md │ │ │ │ ├── PayerValueNode.md │ │ │ │ ├── PdaSeedValueNode.md │ │ │ │ ├── PdaValueNode.md │ │ │ │ ├── ProgramIdValueNode.md │ │ │ │ ├── README.md │ │ │ │ └── ResolverValueNode.md │ │ │ ├── countNodes/ │ │ │ │ ├── FixedCountNode.md │ │ │ │ ├── PrefixedCountNode.md │ │ │ │ ├── README.md │ │ │ │ └── RemainderCountNode.md │ │ │ ├── discriminatorNodes/ │ │ │ │ ├── ConstantDiscriminatorNode.md │ │ │ │ ├── FieldDiscriminatorNode.md │ │ │ │ ├── README.md │ │ │ │ └── SizeDiscriminatorNode.md │ │ │ ├── linkNodes/ │ │ │ │ ├── AccountLinkNode.md │ │ │ │ ├── DefinedTypeLinkNode.md │ │ │ │ ├── InstructionAccountLinkNode.md │ │ │ │ ├── InstructionArgumentLinkNode.md │ │ │ │ ├── InstructionLinkNode.md │ │ │ │ ├── PdaLinkNode.md │ │ │ │ ├── ProgramLinkNode.md │ │ │ │ └── README.md │ │ │ ├── pdaSeedNodes/ │ │ │ │ ├── ConstantPdaSeedNode.md │ │ │ │ ├── README.md │ │ │ │ └── VariablePdaSeedNode.md │ │ │ ├── typeNodes/ │ │ │ │ ├── AmountTypeNode.md │ │ │ │ ├── ArrayTypeNode.md │ │ │ │ ├── BooleanTypeNode.md │ │ │ │ ├── BytesTypeNode.md │ │ │ │ ├── DateTimeTypeNode.md │ │ │ │ ├── EnumEmptyVariantTypeNode.md │ │ │ │ ├── EnumStructVariantTypeNode.md │ │ │ │ ├── EnumTupleVariantTypeNode.md │ │ │ │ ├── EnumTypeNode.md │ │ │ │ ├── EnumVariantTypeNode.md │ │ │ │ ├── FixedSizeTypeNode.md │ │ │ │ ├── HiddenPrefixTypeNode.md │ │ │ │ ├── HiddenSuffixTypeNode.md │ │ │ │ ├── MapTypeNode.md │ │ │ │ ├── NestedTypeNode.md │ │ │ │ ├── NumberTypeNode.md │ │ │ │ ├── OptionTypeNode.md │ │ │ │ ├── PostOffsetTypeNode.md │ │ │ │ ├── PreOffsetTypeNode.md │ │ │ │ ├── PublicKeyTypeNode.md │ │ │ │ ├── README.md │ │ │ │ ├── RemainderOptionTypeNode.md │ │ │ │ ├── SentinelTypeNode.md │ │ │ │ ├── SetTypeNode.md │ │ │ │ ├── SizePrefixTypeNode.md │ │ │ │ ├── SolAmountTypeNode.md │ │ │ │ ├── StringTypeNode.md │ │ │ │ ├── StructFieldTypeNode.md │ │ │ │ ├── StructTypeNode.md │ │ │ │ ├── TupleTypeNode.md │ │ │ │ └── ZeroableOptionTypeNode.md │ │ │ └── valueNodes/ │ │ │ ├── ArrayValueNode.md │ │ │ ├── BooleanValueNode.md │ │ │ ├── BytesValueNode.md │ │ │ ├── ConstantValueNode.md │ │ │ ├── EnumValueNode.md │ │ │ ├── MapEntryValueNode.md │ │ │ ├── MapValueNode.md │ │ │ ├── NoneValueNode.md │ │ │ ├── NumberValueNode.md │ │ │ ├── PublicKeyValueNode.md │ │ │ ├── README.md │ │ │ ├── SetValueNode.md │ │ │ ├── SomeValueNode.md │ │ │ ├── StringValueNode.md │ │ │ ├── StructFieldValueNode.md │ │ │ ├── StructValueNode.md │ │ │ └── TupleValueNode.md │ │ ├── package.json │ │ ├── src/ │ │ │ ├── AccountNode.ts │ │ │ ├── DefinedTypeNode.ts │ │ │ ├── ErrorNode.ts │ │ │ ├── EventNode.ts │ │ │ ├── InstructionAccountNode.ts │ │ │ ├── InstructionArgumentNode.ts │ │ │ ├── InstructionByteDeltaNode.ts │ │ │ ├── InstructionNode.ts │ │ │ ├── InstructionRemainingAccountsNode.ts │ │ │ ├── InstructionStatusNode.ts │ │ │ ├── Node.ts │ │ │ ├── PdaNode.ts │ │ │ ├── ProgramNode.ts │ │ │ ├── RootNode.ts │ │ │ ├── contextualValueNodes/ │ │ │ │ ├── AccountBumpValueNode.ts │ │ │ │ ├── AccountValueNode.ts │ │ │ │ ├── ArgumentValueNode.ts │ │ │ │ ├── ConditionalValueNode.ts │ │ │ │ ├── ContextualValueNode.ts │ │ │ │ ├── IdentityValueNode.ts │ │ │ │ ├── PayerValueNode.ts │ │ │ │ ├── PdaSeedValueNode.ts │ │ │ │ ├── PdaValueNode.ts │ │ │ │ ├── ProgramIdValueNode.ts │ │ │ │ ├── ResolverValueNode.ts │ │ │ │ └── index.ts │ │ │ ├── countNodes/ │ │ │ │ ├── CountNode.ts │ │ │ │ ├── FixedCountNode.ts │ │ │ │ ├── PrefixedCountNode.ts │ │ │ │ ├── RemainderCountNode.ts │ │ │ │ └── index.ts │ │ │ ├── discriminatorNodes/ │ │ │ │ ├── ConstantDiscriminatorNode.ts │ │ │ │ ├── DiscriminatorNode.ts │ │ │ │ ├── FieldDiscriminatorNode.ts │ │ │ │ ├── SizeDiscriminatorNode.ts │ │ │ │ └── index.ts │ │ │ ├── index.ts │ │ │ ├── linkNodes/ │ │ │ │ ├── AccountLinkNode.ts │ │ │ │ ├── DefinedTypeLinkNode.ts │ │ │ │ ├── InstructionAccountLinkNode.ts │ │ │ │ ├── InstructionArgumentLinkNode.ts │ │ │ │ ├── InstructionLinkNode.ts │ │ │ │ ├── LinkNode.ts │ │ │ │ ├── PdaLinkNode.ts │ │ │ │ ├── ProgramLinkNode.ts │ │ │ │ └── index.ts │ │ │ ├── pdaSeedNodes/ │ │ │ │ ├── ConstantPdaSeedNode.ts │ │ │ │ ├── PdaSeedNode.ts │ │ │ │ ├── VariablePdaSeedNode.ts │ │ │ │ └── index.ts │ │ │ ├── shared/ │ │ │ │ ├── docs.ts │ │ │ │ ├── index.ts │ │ │ │ └── stringCases.ts │ │ │ ├── typeNodes/ │ │ │ │ ├── AmountTypeNode.ts │ │ │ │ ├── ArrayTypeNode.ts │ │ │ │ ├── BooleanTypeNode.ts │ │ │ │ ├── BytesTypeNode.ts │ │ │ │ ├── DateTimeTypeNode.ts │ │ │ │ ├── EnumEmptyVariantTypeNode.ts │ │ │ │ ├── EnumStructVariantTypeNode.ts │ │ │ │ ├── EnumTupleVariantTypeNode.ts │ │ │ │ ├── EnumTypeNode.ts │ │ │ │ ├── EnumVariantTypeNode.ts │ │ │ │ ├── FixedSizeTypeNode.ts │ │ │ │ ├── HiddenPrefixTypeNode.ts │ │ │ │ ├── HiddenSuffixTypeNode.ts │ │ │ │ ├── MapTypeNode.ts │ │ │ │ ├── NestedTypeNode.ts │ │ │ │ ├── NumberTypeNode.ts │ │ │ │ ├── OptionTypeNode.ts │ │ │ │ ├── PostOffsetTypeNode.ts │ │ │ │ ├── PreOffsetTypeNode.ts │ │ │ │ ├── PublicKeyTypeNode.ts │ │ │ │ ├── RemainderOptionTypeNode.ts │ │ │ │ ├── SentinelTypeNode.ts │ │ │ │ ├── SetTypeNode.ts │ │ │ │ ├── SizePrefixTypeNode.ts │ │ │ │ ├── SolAmountTypeNode.ts │ │ │ │ ├── StringTypeNode.ts │ │ │ │ ├── StructFieldTypeNode.ts │ │ │ │ ├── StructTypeNode.ts │ │ │ │ ├── TupleTypeNode.ts │ │ │ │ ├── TypeNode.ts │ │ │ │ ├── ZeroableOptionTypeNode.ts │ │ │ │ └── index.ts │ │ │ ├── types/ │ │ │ │ └── global.d.ts │ │ │ └── valueNodes/ │ │ │ ├── ArrayValueNode.ts │ │ │ ├── BooleanValueNode.ts │ │ │ ├── BytesValueNode.ts │ │ │ ├── ConstantValueNode.ts │ │ │ ├── EnumValueNode.ts │ │ │ ├── MapEntryValueNode.ts │ │ │ ├── MapValueNode.ts │ │ │ ├── NoneValueNode.ts │ │ │ ├── NumberValueNode.ts │ │ │ ├── PublicKeyValueNode.ts │ │ │ ├── SetValueNode.ts │ │ │ ├── SomeValueNode.ts │ │ │ ├── StringValueNode.ts │ │ │ ├── StructFieldValueNode.ts │ │ │ ├── StructValueNode.ts │ │ │ ├── TupleValueNode.ts │ │ │ ├── ValueNode.ts │ │ │ └── index.ts │ │ ├── test/ │ │ │ ├── AccountNode.test.ts │ │ │ ├── DefinedTypeNode.test.ts │ │ │ ├── ErrorNode.test.ts │ │ │ ├── EventNode.test.ts │ │ │ ├── InstructionAccountNode.test.ts │ │ │ ├── InstructionArgumentNode.test.ts │ │ │ ├── InstructionByteDeltaNode.test.ts │ │ │ ├── InstructionNode.test.ts │ │ │ ├── InstructionRemainingAccountsNode.test.ts │ │ │ ├── InstructionStatusNode.test.ts │ │ │ ├── Node.test.ts │ │ │ ├── Node.typetest.ts │ │ │ ├── PdaNode.test.ts │ │ │ ├── ProgramNode.test.ts │ │ │ ├── RootNode.test.ts │ │ │ ├── contextualValueNodes/ │ │ │ │ ├── AccountBumpValueNode.test.ts │ │ │ │ ├── AccountValueNode.test.ts │ │ │ │ ├── ArgumentValueNode.test.ts │ │ │ │ ├── ConditionalValueNode.test.ts │ │ │ │ ├── ContextualValueNode.typetest.ts │ │ │ │ ├── IdentityValueNode.test.ts │ │ │ │ ├── PayerValueNode.test.ts │ │ │ │ ├── PdaSeedValueNode.test.ts │ │ │ │ ├── PdaValueNode.test.ts │ │ │ │ ├── ProgramIdValueNode.test.ts │ │ │ │ └── ResolverValueNode.test.ts │ │ │ ├── countNodes/ │ │ │ │ ├── CountNode.typetest.ts │ │ │ │ ├── FixedCountNode.test.ts │ │ │ │ ├── PrefixedCountNode.test.ts │ │ │ │ └── RemainderCountNode.test.ts │ │ │ ├── discriminatorNodes/ │ │ │ │ ├── ConstantDiscriminatorNode.test.ts │ │ │ │ ├── DiscriminatorNode.typetest.ts │ │ │ │ ├── FieldDiscriminatorNode.test.ts │ │ │ │ └── SizeDiscriminatorNode.test.ts │ │ │ ├── linkNodes/ │ │ │ │ ├── AccountLinkNode.test.ts │ │ │ │ ├── DefinedTypeLinkNode.test.ts │ │ │ │ ├── InstructionAccountLinkNode.test.ts │ │ │ │ ├── InstructionArgumentLinkNode.test.ts │ │ │ │ ├── InstructionLinkNode.test.ts │ │ │ │ ├── LinkNode.typetest.ts │ │ │ │ ├── PdaLinkNode.test.ts │ │ │ │ └── ProgramLinkNode.test.ts │ │ │ ├── pdaSeedNodes/ │ │ │ │ ├── ConstantPdaSeedNode.test.ts │ │ │ │ ├── PdaSeedNode.typetest.ts │ │ │ │ └── VariablePdaSeedNode.test.ts │ │ │ ├── shared/ │ │ │ │ └── stringCases.test.ts │ │ │ ├── typeNodes/ │ │ │ │ ├── AmountTypeNode.test.ts │ │ │ │ ├── ArrayTypeNode.test.ts │ │ │ │ ├── BooleanTypeNode.test.ts │ │ │ │ ├── BytesTypeNode.test.ts │ │ │ │ ├── DateTimeTypeNode.test.ts │ │ │ │ ├── EnumEmptyVariantTypeNode.test.ts │ │ │ │ ├── EnumStructVariantTypeNode.test.ts │ │ │ │ ├── EnumTupleVariantTypeNode.test.ts │ │ │ │ ├── EnumTypeNode.test.ts │ │ │ │ ├── FixedSizeTypeNode.test.ts │ │ │ │ ├── HiddenPrefixTypeNode.test.ts │ │ │ │ ├── HiddenSuffixTypeNode.test.ts │ │ │ │ ├── MapTypeNode.test.ts │ │ │ │ ├── NestedTypeNode.test.ts │ │ │ │ ├── NestedTypeNode.typetest.ts │ │ │ │ ├── NumberTypeNode.test.ts │ │ │ │ ├── OptionTypeNode.test.ts │ │ │ │ ├── PostOffsetTypeNode.test.ts │ │ │ │ ├── PreOffsetTypeNode.test.ts │ │ │ │ ├── PublicKeyTypeNode.test.ts │ │ │ │ ├── RemainderOptionTypeNode.test.ts │ │ │ │ ├── SentinelTypeNode.test.ts │ │ │ │ ├── SetTypeNode.test.ts │ │ │ │ ├── SizePrefixTypeNode.test.ts │ │ │ │ ├── SolAmountTypeNode.test.ts │ │ │ │ ├── StringTypeNode.test.ts │ │ │ │ ├── StructFieldTypeNode.test.ts │ │ │ │ ├── StructTypeNode.test.ts │ │ │ │ ├── TupleTypeNode.test.ts │ │ │ │ ├── TypeNode.typetest.ts │ │ │ │ └── ZeroableOptionTypeNode.test.ts │ │ │ ├── types/ │ │ │ │ └── global.d.ts │ │ │ └── valueNodes/ │ │ │ ├── ArrayValueNode.test.ts │ │ │ ├── BooleanValueNode.test.ts │ │ │ ├── BytesValueNode.test.ts │ │ │ ├── ConstantValueNode.test.ts │ │ │ ├── EnumValueNode.test.ts │ │ │ ├── MapEntryValueNode.test.ts │ │ │ ├── MapValueNode.test.ts │ │ │ ├── NoneValueNode.test.ts │ │ │ ├── NumberValueNode.test.ts │ │ │ ├── PublicKeyValueNode.test.ts │ │ │ ├── SetValueNode.test.ts │ │ │ ├── SomeValueNode.test.ts │ │ │ ├── StringValueNode.test.ts │ │ │ ├── StructFieldValueNode.test.ts │ │ │ ├── StructValueNode.test.ts │ │ │ ├── TupleValueNode.test.ts │ │ │ └── ValueNode.typetest.ts │ │ ├── tsconfig.declarations.json │ │ ├── tsconfig.json │ │ ├── tsup.config.ts │ │ └── vitest.config.mts │ ├── nodes-from-anchor/ │ │ ├── .gitignore │ │ ├── .prettierignore │ │ ├── LICENSE │ │ ├── README.md │ │ ├── package.json │ │ ├── src/ │ │ │ ├── defaultVisitor.ts │ │ │ ├── discriminators.ts │ │ │ ├── extractPdasVisitor.ts │ │ │ ├── index.ts │ │ │ ├── utils.ts │ │ │ ├── v00/ │ │ │ │ ├── AccountNode.ts │ │ │ │ ├── DefinedTypeNode.ts │ │ │ │ ├── ErrorNode.ts │ │ │ │ ├── InstructionAccountNode.ts │ │ │ │ ├── InstructionArgumentNode.ts │ │ │ │ ├── InstructionNode.ts │ │ │ │ ├── PdaNode.ts │ │ │ │ ├── ProgramNode.ts │ │ │ │ ├── RootNode.ts │ │ │ │ ├── idl.ts │ │ │ │ ├── index.ts │ │ │ │ └── typeNodes/ │ │ │ │ ├── ArrayTypeNode.ts │ │ │ │ ├── EnumEmptyVariantTypeNode.ts │ │ │ │ ├── EnumStructVariantTypeNode.ts │ │ │ │ ├── EnumTupleVariantTypeNode.ts │ │ │ │ ├── EnumTypeNode.ts │ │ │ │ ├── MapTypeNode.ts │ │ │ │ ├── OptionTypeNode.ts │ │ │ │ ├── SetTypeNode.ts │ │ │ │ ├── StructFieldTypeNode.ts │ │ │ │ ├── StructTypeNode.ts │ │ │ │ ├── TupleTypeNode.ts │ │ │ │ ├── TypeNode.ts │ │ │ │ └── index.ts │ │ │ └── v01/ │ │ │ ├── AccountNode.ts │ │ │ ├── DefinedTypeNode.ts │ │ │ ├── ErrorNode.ts │ │ │ ├── EventNode.ts │ │ │ ├── InstructionAccountNode.ts │ │ │ ├── InstructionArgumentNode.ts │ │ │ ├── InstructionNode.ts │ │ │ ├── PdaSeedNode.ts │ │ │ ├── ProgramNode.ts │ │ │ ├── RootNode.ts │ │ │ ├── idl.ts │ │ │ ├── index.ts │ │ │ ├── typeNodes/ │ │ │ │ ├── ArrayTypeNode.ts │ │ │ │ ├── EnumEmptyVariantTypeNode.ts │ │ │ │ ├── EnumStructVariantTypeNode.ts │ │ │ │ ├── EnumTupleVariantTypeNode.ts │ │ │ │ ├── EnumTypeNode.ts │ │ │ │ ├── OptionTypeNode.ts │ │ │ │ ├── StructFieldTypeNode.ts │ │ │ │ ├── StructTypeNode.ts │ │ │ │ ├── TupleTypeNode.ts │ │ │ │ ├── TypeNode.ts │ │ │ │ └── index.ts │ │ │ └── unwrapGenerics.ts │ │ ├── test/ │ │ │ ├── discriminator.test.ts │ │ │ ├── rootNodeFromAnchor.test.ts │ │ │ ├── v00/ │ │ │ │ ├── AccountNode.test.ts │ │ │ │ ├── DefinedTypeNode.test.ts │ │ │ │ ├── ErrorNode.test.ts │ │ │ │ ├── InstructionAccountNode.test.ts │ │ │ │ ├── InstructionArgumentNode.test.ts │ │ │ │ ├── InstructionNode.test.ts │ │ │ │ ├── PdaNode.test.ts │ │ │ │ ├── ProgramNode.test.ts │ │ │ │ ├── RootNode.test.ts │ │ │ │ └── typeNodes/ │ │ │ │ ├── ArrayTypeNode.test.ts │ │ │ │ ├── BooleanTypeNode.test.ts │ │ │ │ ├── BytesTypeNode.test.ts │ │ │ │ ├── EnumTypeNode.test.ts │ │ │ │ ├── MapTypeNode.test.ts │ │ │ │ ├── NumberTypeNode.test.ts │ │ │ │ ├── OptionTypeNode.test.ts │ │ │ │ ├── PublicKeyTypeNode.test.ts │ │ │ │ ├── SetTypeNode.test.ts │ │ │ │ ├── StringTypeNode.test.ts │ │ │ │ ├── StructTypeNode.test.ts │ │ │ │ └── TupleTypeNode.test.ts │ │ │ └── v01/ │ │ │ ├── AccountNode.test.ts │ │ │ ├── DefinedTypeNode.test.ts │ │ │ ├── ErrorNode.test.ts │ │ │ ├── EventNode.test.ts │ │ │ ├── InstructionAccountNode.test.ts │ │ │ ├── InstructionArgumentNode.test.ts │ │ │ ├── InstructionNode.test.ts │ │ │ ├── ProgramNode.test.ts │ │ │ ├── RootNode.test.ts │ │ │ ├── extractPdasVisitor.test.ts │ │ │ ├── pdaSeedNode.test.ts │ │ │ └── typeNodes/ │ │ │ ├── ArrayTypeNode.test.ts │ │ │ ├── BooleanTypeNode.test.ts │ │ │ ├── BytesTypeNode.test.ts │ │ │ ├── EnumTypeNode.test.ts │ │ │ ├── NumberTypeNode.test.ts │ │ │ ├── OptionTypeNode.test.ts │ │ │ ├── PublicKeyTypeNode.test.ts │ │ │ ├── StringTypeNode.test.ts │ │ │ ├── StructTypeNode.test.ts │ │ │ └── TupleTypeNode.test.ts │ │ ├── tsconfig.declarations.json │ │ ├── tsconfig.json │ │ ├── tsup.config.ts │ │ └── vitest.config.mts │ ├── renderers-core/ │ │ ├── .gitignore │ │ ├── .prettierignore │ │ ├── LICENSE │ │ ├── README.md │ │ ├── package.json │ │ ├── src/ │ │ │ ├── fragment.ts │ │ │ ├── fs.ts │ │ │ ├── index.ts │ │ │ ├── path.ts │ │ │ ├── renderMap.ts │ │ │ └── types/ │ │ │ └── global.d.ts │ │ ├── test/ │ │ │ ├── fs.test.json │ │ │ ├── fs.test.ts │ │ │ ├── path.test.ts │ │ │ ├── renderMap.test.ts │ │ │ └── types/ │ │ │ └── global.d.ts │ │ ├── tsconfig.declarations.json │ │ ├── tsconfig.json │ │ ├── tsup.config.ts │ │ └── vitest.config.mts │ ├── validators/ │ │ ├── .gitignore │ │ ├── .prettierignore │ │ ├── LICENSE │ │ ├── README.md │ │ ├── package.json │ │ ├── src/ │ │ │ ├── ValidationItem.ts │ │ │ ├── getValidationItemsVisitor.ts │ │ │ ├── index.ts │ │ │ └── throwValidatorItemsVisitor.ts │ │ ├── test/ │ │ │ └── getValidationItemsVisitor.test.ts │ │ ├── tsconfig.declarations.json │ │ ├── tsconfig.json │ │ ├── tsup.config.ts │ │ └── vitest.config.mts │ ├── visitors/ │ │ ├── .gitignore │ │ ├── .prettierignore │ │ ├── LICENSE │ │ ├── README.md │ │ ├── package.json │ │ ├── src/ │ │ │ ├── addPdasVisitor.ts │ │ │ ├── createSubInstructionsFromEnumArgsVisitor.ts │ │ │ ├── deduplicateIdenticalDefinedTypesVisitor.ts │ │ │ ├── fillDefaultPdaSeedValuesVisitor.ts │ │ │ ├── flattenInstructionDataArgumentsVisitor.ts │ │ │ ├── flattenStructVisitor.ts │ │ │ ├── getDefinedTypeHistogramVisitor.ts │ │ │ ├── index.ts │ │ │ ├── renameHelpers.ts │ │ │ ├── setAccountDiscriminatorFromFieldVisitor.ts │ │ │ ├── setFixedAccountSizesVisitor.ts │ │ │ ├── setInstructionAccountDefaultValuesVisitor.ts │ │ │ ├── setInstructionDiscriminatorsVisitor.ts │ │ │ ├── setNumberWrappersVisitor.ts │ │ │ ├── setStructDefaultValuesVisitor.ts │ │ │ ├── transformDefinedTypesIntoAccountsVisitor.ts │ │ │ ├── transformU8ArraysToBytesVisitor.ts │ │ │ ├── unwrapDefinedTypesVisitor.ts │ │ │ ├── unwrapInstructionArgsDefinedTypesVisitor.ts │ │ │ ├── unwrapTupleEnumWithSingleStructVisitor.ts │ │ │ ├── unwrapTypeDefinedLinksVisitor.ts │ │ │ ├── updateAccountsVisitor.ts │ │ │ ├── updateDefinedTypesVisitor.ts │ │ │ ├── updateErrorsVisitor.ts │ │ │ ├── updateInstructionsVisitor.ts │ │ │ └── updateProgramsVisitor.ts │ │ ├── test/ │ │ │ ├── addPdasVisitor.test.ts │ │ │ ├── fillDefaultPdaSeedValuesVisitor.test.ts │ │ │ ├── getDefinedTypeHistogramVisitor.test.ts │ │ │ ├── setStructDefaultValuesVisitor.test.ts │ │ │ ├── unwrapDefinedTypesVisitor.test.ts │ │ │ ├── unwrapInstructionArgsDefinedTypesVisitor.test.ts │ │ │ ├── updateAccountsVisitor.test.ts │ │ │ └── updateInstructionsVisitor.test.ts │ │ ├── tsconfig.declarations.json │ │ ├── tsconfig.json │ │ ├── tsup.config.ts │ │ └── vitest.config.mts │ └── visitors-core/ │ ├── .gitignore │ ├── .prettierignore │ ├── LICENSE │ ├── README.md │ ├── package.json │ ├── src/ │ │ ├── LinkableDictionary.ts │ │ ├── NodePath.ts │ │ ├── NodeSelector.ts │ │ ├── NodeStack.ts │ │ ├── bottomUpTransformerVisitor.ts │ │ ├── consoleLogVisitor.ts │ │ ├── deleteNodesVisitor.ts │ │ ├── extendVisitor.ts │ │ ├── getByteSizeVisitor.ts │ │ ├── getDebugStringVisitor.ts │ │ ├── getMaxByteSizeVisitor.ts │ │ ├── getResolvedInstructionInputsVisitor.ts │ │ ├── getUniqueHashStringVisitor.ts │ │ ├── identityVisitor.ts │ │ ├── index.ts │ │ ├── interceptFirstVisitVisitor.ts │ │ ├── interceptVisitor.ts │ │ ├── mapVisitor.ts │ │ ├── mergeVisitor.ts │ │ ├── nonNullableIdentityVisitor.ts │ │ ├── pipe.ts │ │ ├── recordLinkablesVisitor.ts │ │ ├── recordNodeStackVisitor.ts │ │ ├── removeDocsVisitor.ts │ │ ├── singleNodeVisitor.ts │ │ ├── staticVisitor.ts │ │ ├── tapVisitor.ts │ │ ├── topDownTransformerVisitor.ts │ │ ├── visitor.ts │ │ └── voidVisitor.ts │ ├── test/ │ │ ├── NodeSelector.test.ts │ │ ├── bottomUpTransformerVisitor.test.ts │ │ ├── deleteNodesVisitor.test.ts │ │ ├── extendVisitor.test.ts │ │ ├── getByteSizeVisitor.test.ts │ │ ├── getDebugStringVisitor.test.ts │ │ ├── getMaxByteSizeVisitor.test.ts │ │ ├── getResolvedInstructionInputsVisitor.test.ts │ │ ├── getUniqueHashStringVisitor.test.ts │ │ ├── identityVisitor.test.ts │ │ ├── interceptFirstVisitVisitor.test.ts │ │ ├── interceptVisitor.test.ts │ │ ├── mapVisitor.test.ts │ │ ├── mergeVisitor.test.ts │ │ ├── nodes/ │ │ │ ├── AccountNode.test.ts │ │ │ ├── DefinedTypeNode.test.ts │ │ │ ├── ErrorNode.test.ts │ │ │ ├── EventNode.test.ts │ │ │ ├── InstructionAccountNode.test.ts │ │ │ ├── InstructionArgumentNode.test.ts │ │ │ ├── InstructionByteDeltaNode.test.ts │ │ │ ├── InstructionNode.test.ts │ │ │ ├── InstructionRemainingAccountsNode.test.ts │ │ │ ├── PdaNode.test.ts │ │ │ ├── ProgramNode.test.ts │ │ │ ├── RootNode.test.ts │ │ │ ├── _setup.ts │ │ │ ├── contextualValueNodes/ │ │ │ │ ├── AccountBumpValueNode.test.ts │ │ │ │ ├── AccountValueNode.test.ts │ │ │ │ ├── ArgumentValueNode.test.ts │ │ │ │ ├── ConditionalValueNode.test.ts │ │ │ │ ├── IdentityValueNode.test.ts │ │ │ │ ├── PayerValueNode.test.ts │ │ │ │ ├── PdaSeedValueNode.test.ts │ │ │ │ ├── PdaValueNode.test.ts │ │ │ │ ├── ProgramIdValueNode.test.ts │ │ │ │ └── ResolverValueNode.test.ts │ │ │ ├── discriminatorNodes/ │ │ │ │ ├── ConstantDiscriminatorNode.test.ts │ │ │ │ ├── FieldDiscriminatorNode.test.ts │ │ │ │ └── SizeDiscriminatorNode.test.ts │ │ │ ├── linkNodes/ │ │ │ │ ├── AccountLinkNode.test.ts │ │ │ │ ├── DefinedTypeLinkNode.test.ts │ │ │ │ ├── InstructionAccountLinkNode.test.ts │ │ │ │ ├── InstructionArgumentLinkNode.test.ts │ │ │ │ ├── InstructionLinkNode.test.ts │ │ │ │ ├── PdaLinkNode.test.ts │ │ │ │ └── ProgramLinkNode.test.ts │ │ │ ├── pdaSeedNodes/ │ │ │ │ ├── ConstantPdaSeedNode.test.ts │ │ │ │ └── VariablePdaSeedNode.test.ts │ │ │ ├── sizeNodes/ │ │ │ │ ├── FixedSizeNode.test.ts │ │ │ │ ├── PrefixedSizeNode.test.ts │ │ │ │ └── RemainderSizeNode.test.ts │ │ │ ├── typeNodes/ │ │ │ │ ├── AmountTypeNode.test.ts │ │ │ │ ├── ArrayTypeNode.test.ts │ │ │ │ ├── BooleanTypeNode.test.ts │ │ │ │ ├── BytesTypeNode.test.ts │ │ │ │ ├── DateTimeTypeNode.test.ts │ │ │ │ ├── EnumEmptyVariantTypeNode.test.ts │ │ │ │ ├── EnumStructVariantTypeNode.test.ts │ │ │ │ ├── EnumTupleVariantTypeNode.test.ts │ │ │ │ ├── EnumTypeNode.test.ts │ │ │ │ ├── FixedSizeTypeNode.test.ts │ │ │ │ ├── HiddenPrefixTypeNode.test.ts │ │ │ │ ├── HiddenSuffixTypeNode.test.ts │ │ │ │ ├── MapTypeNode.test.ts │ │ │ │ ├── NumberTypeNode.test.ts │ │ │ │ ├── OptionTypeNode.test.ts │ │ │ │ ├── PostOffsetTypeNode.test.ts │ │ │ │ ├── PreOffsetTypeNode.test.ts │ │ │ │ ├── PublicKeyTypeNode.test.ts │ │ │ │ ├── RemainderOptionTypeNode.test.ts │ │ │ │ ├── SentinelTypeNode.test.ts │ │ │ │ ├── SetTypeNode.test.ts │ │ │ │ ├── SizePrefixTypeNode.test.ts │ │ │ │ ├── SolAmountTypeNode.test.ts │ │ │ │ ├── StringTypeNode.test.ts │ │ │ │ ├── StructFieldTypeNode.test.ts │ │ │ │ ├── StructTypeNode.test.ts │ │ │ │ ├── TupleTypeNode.test.ts │ │ │ │ └── ZeroableOptionTypeNode.test.ts │ │ │ └── valueNodes/ │ │ │ ├── ArrayValueNode.test.ts │ │ │ ├── BooleanValueNode.test.ts │ │ │ ├── BytesValueNode.test.ts │ │ │ ├── ConstantValueNode.test.ts │ │ │ ├── EnumValueNode.test.ts │ │ │ ├── MapEntryValueNode.test.ts │ │ │ ├── MapValueNode.test.ts │ │ │ ├── NoneValueNode.test.ts │ │ │ ├── NumberValueNode.test.ts │ │ │ ├── PublicKeyValueNode.test.ts │ │ │ ├── SetValueNode.test.ts │ │ │ ├── SomeValueNode.test.ts │ │ │ ├── StringValueNode.test.ts │ │ │ ├── StructFieldValueNode.test.ts │ │ │ ├── StructValueNode.test.ts │ │ │ └── TupleValueNode.test.ts │ │ ├── nonNullableIdentityVisitor.test.ts │ │ ├── recordLinkablesVisitor.test.ts │ │ ├── recordNodeStackVisitor.test.ts │ │ ├── removeDocsVisitor.test.ts │ │ ├── singleNodeVisitor.test.ts │ │ ├── staticVisitor.test.ts │ │ ├── tapVisitor.test.ts │ │ ├── topDownTransformerVisitor.test.ts │ │ ├── visitor.test.ts │ │ └── voidVisitor.test.ts │ ├── tsconfig.declarations.json │ ├── tsconfig.json │ ├── tsup.config.ts │ └── vitest.config.mts ├── pnpm-workspace.yaml ├── tsconfig.json ├── tsup.config.base.ts ├── turbo.json ├── vitest.config.base.mts └── vitest.config.mts ================================================ FILE CONTENTS ================================================ ================================================ FILE: .changeset/README.md ================================================ # Changesets Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works with multi-package repos, or single-package repos to help you version and publish your code. You can find the full documentation for it [in our repository](https://github.com/changesets/changesets) We have a quick list of common questions to get you started engaging with this project in [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) ================================================ FILE: .changeset/config.json ================================================ { "$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json", "changelog": [ "@changesets/changelog-github", { "repo": "codama-idl/codama" } ], "commit": false, "fixed": [ [ "codama", "@codama/errors", "@codama/node-types", "@codama/nodes", "@codama/validators", "@codama/visitors*" ] ], "linked": [], "access": "public", "baseBranch": "main", "privatePackages": { "version": false, "tag": false }, "updateInternalDependencies": "patch" } ================================================ FILE: .github/actions/setup-anchor/action.yml ================================================ name: Setup Anchor CLI description: Install Rust toolchain and a pinned Anchor CLI version via AVM with caching for CI. inputs: anchor-version: description: Anchor CLI version to install (e.g. 0.32.1) required: true rust-version: description: Rust toolchain version to install (e.g. 1.93.0) required: true cargo-lock-path: description: Path to Cargo.lock for cache key hashing required: false default: packages/dynamic-client/test/programs/anchor/Cargo.lock build-target-path: description: Path to the build target directory to cache required: false default: packages/dynamic-client/test/programs/anchor/target runs: using: composite steps: - name: Setup Rust uses: dtolnay/rust-toolchain@stable with: toolchain: ${{ inputs.rust-version }} - name: Cache Rust and Anchor toolchain uses: actions/cache@v4 with: path: | ~/.cargo/registry ~/.cargo/git ~/.cargo/bin/avm ~/.avm ${{ inputs.build-target-path }} key: ${{ runner.os }}-rust-anchor-${{ inputs.rust-version }}-${{ inputs.anchor-version }}-${{ inputs.cargo-lock-path && hashFiles(inputs.cargo-lock-path) || 'no-lock' }} restore-keys: | ${{ runner.os }}-rust-anchor-${{ inputs.rust-version }}-${{ inputs.anchor-version }}- ${{ runner.os }}-rust-anchor-${{ inputs.rust-version }}- - name: Install Anchor (pinned) shell: bash run: | set -euo pipefail echo "$HOME/.cargo/bin" >> "$GITHUB_PATH" echo "$HOME/.avm/bin" >> "$GITHUB_PATH" export PATH="$HOME/.cargo/bin:$HOME/.avm/bin:$PATH" desired="${{ inputs.anchor-version }}" # Install AVM if needed. if ! command -v avm >/dev/null 2>&1; then sudo apt-get update sudo apt-get install -y pkg-config libssl-dev cargo install --git https://github.com/coral-xyz/anchor avm --locked fi # Ensure the desired Anchor version exists and is active. avm install "$desired" avm use "$desired" anchor --version ================================================ FILE: .github/dependabot.yml ================================================ version: 2 updates: - package-ecosystem: 'npm' directory: '/' schedule: interval: daily time: '01:00' timezone: America/Los_Angeles open-pull-requests-limit: 10 ================================================ FILE: .github/workflows/main.yml ================================================ name: Main on: push: branches: [main] pull_request: env: # Among other things, opts out of Turborepo telemetry. See https://consoledonottrack.com/. DO_NOT_TRACK: '1' NODE_VERSION: 20 CODAMA_VERSION: 1.x SOLANA_VERSION: 3.1.8 ANCHOR_VERSION: '0.32.1' RUST_VERSION: '1.93.0' jobs: lint: name: Check styling runs-on: ubuntu-latest steps: - name: Git checkout uses: actions/checkout@v4 - name: Setup pnpm uses: pnpm/action-setup@v3 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} cache: 'pnpm' - name: Install dependencies run: pnpm install --frozen-lockfile - name: Compile JS and types run: pnpm run build - name: Check linting run: pnpm run lint tests: name: Test runs-on: ubuntu-latest steps: - name: Git checkout uses: actions/checkout@v4 - name: Install Solana uses: solana-program/actions/install-solana@v1 with: version: ${{ env.SOLANA_VERSION }} - name: Setup Anchor uses: ./.github/actions/setup-anchor with: anchor-version: ${{ env.ANCHOR_VERSION }} rust-version: ${{ env.RUST_VERSION }} - name: Install pnpm uses: pnpm/action-setup@v3 - name: Setup Node.js ${{ env.NODE_VERSION }} uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} cache: 'pnpm' - name: Install dependencies run: pnpm install --frozen-lockfile - name: Build and run tests run: pnpm run test - name: Ensure working directory is clean run: | git status test -z "$(git status --porcelain)" release: name: Release runs-on: ubuntu-latest if: github.event_name == 'push' needs: [lint, tests] permissions: contents: write pull-requests: write outputs: published: ${{ steps.changesets.outputs.published }} steps: - name: Checkout Repo uses: actions/checkout@v4 - name: Setup pnpm uses: pnpm/action-setup@v3 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} cache: 'pnpm' - name: Install Dependencies run: pnpm install --frozen-lockfile - name: Create Release Pull Request or Publish id: changesets uses: changesets/action@v1 with: commit: '[${{ env.CODAMA_VERSION }}] Publish packages' title: '[${{ env.CODAMA_VERSION }}] Publish packages' publish: pnpm publish-packages env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} dependabot: runs-on: ubuntu-latest if: github.event_name == 'pull_request' && github.event.pull_request.user.login == 'dependabot[bot]' && github.repository == 'codama-idl/codama' needs: [lint, tests] permissions: contents: write pull-requests: write steps: - name: Auto-approve the PR run: gh pr review --approve "$PR_URL" env: PR_URL: ${{ github.event.pull_request.html_url }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Enable auto-merge run: gh pr merge --auto --squash "$PR_URL" env: PR_URL: ${{ github.event.pull_request.html_url }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} ================================================ FILE: .gitignore ================================================ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. # dependencies node_modules .pnp .pnp.js # misc .DS_Store *.pem # debug npm-debug.log* yarn-debug.log* yarn-error.log* .pnpm-debug.log* # turbo .turbo # `solana-test-validator` .solana/ test-ledger/ target/ CHANGELOG.md ================================================ FILE: .prettierignore ================================================ .changeset/ .github/workflows/PULL_REQUEST_TEMPLATE.md declarations/ dist/ doc/ lib/ test-ledger/ target/ CHANGELOG.md pnpm-lock.yaml pnpm-workspace.yaml ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2025 Codama Copyright (c) 2024 Metaplex Foundation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # Codama [![npm][npm-image]][npm-url] [![npm-downloads][npm-downloads-image]][npm-url] [![ci][ci-image]][ci-url] [npm-downloads-image]: https://img.shields.io/npm/dm/codama.svg?style=flat [npm-image]: https://img.shields.io/npm/v/codama.svg?style=flat [npm-url]: https://www.npmjs.com/package/codama [ci-image]: https://img.shields.io/github/actions/workflow/status/codama-idl/codama/main.yml?logo=GitHub [ci-url]: https://github.com/codama-idl/codama/actions/workflows/main.yml Codama is a tool that describes any Solana program in a standardised format called a **Codama IDL**. A Codama IDL can be used to: - ✨ Generate **program clients** in various languages and frameworks. - 📚 Generate **documentation and tooling** for your programs. - 🗃️ **Register your IDL** for others to discover and index. - 🔭 Provide valuable information to **explorers and wallets**. ![Codama header: A small double-sided mind-map with the Codama logo in the middle. On the left, we see the various ways to get a Codama IDL from your Solana programs such as "Codama Macros" and "Anchor Program". On the right, we see the various utility tools that are offered for the IDL such as "Generate clients" or "Register IDL".](https://github.com/user-attachments/assets/7a2ef5fa-049e-45a8-a5fc-7c11ff46a54b) ## Table of contents - [Getting started](#getting-started). Install and use Codama in your project. - [Coming from Anchor](#coming-from-anchor). Have an Anchor IDL instead? Let’s make that work. - [Codama scripts](#codama-scripts). Enrich your Codama config file with more scripts. - [Available visitors](#available-visitors). See what’s available for you to use. - [Getting a Codama IDL](#getting-a-codama-idl). Extract Codama IDLs from any program. - [Codama’s architecture](#codamas-architecture). A bit more on the node/visitor design. - [Other resources](#other-resources). ## Getting started ### Installation To get started with Codama, simply install `codama` to your project and run the `init` command like so: ```sh pnpm install codama codama init ``` You will be prompted for the path of your IDL and asked to select any script presets you would like to use. This will create a Codama configuration file at the root of your project. ### Usage You may then use the `codama run` command to execute any script defined in your configuration file. ```sh codama run --all # Run all Codama scripts. codama run js # Generates a JavaScript client. codama run rust # Generates a Rust client. ``` ## Coming from Anchor If you are using [Anchor](https://www.anchor-lang.com/docs) or [Shank macros](https://github.com/metaplex-foundation/shank), then you should already have an **Anchor IDL**. To make it work with Codama, you simply need to provide the path to your Anchor IDL in your Codama configuration file. Codama will automatically identify this as an Anchor IDL and will convert it to a Codama IDL before executing your scripts. ```json { "idl": "path/to/my/anchor/idl.json" } ``` ## Codama scripts You can use your Codama configuration file to define any script you want by using one or more visitors that will be invoked when the script is ran. **Visitors** are objects that will visit your Codama IDL and either perform some operation — like generating a program client — or update the IDL further — like renaming accounts. You can either use visitors from external packages or from a local file, and — in both cases — you can provide any argument the visitor may require. For instance, the example script below will invoke three visitors: - The first will use the `default` import from the `my-external-visitor` package and pass `42` as the first argument. - The second will use the `withDefaults` import from the `my-external-visitor` package. - The third will use a local visitor located next to the configuration file. ```json { "scripts": { "my-script": [ { "from": "my-external-visitor", "args": [42] }, "my-external-visitor#withDefaults", "./my-local-visitor.js" ] } } ``` Note that if an external visitor in your script isn’t installed locally, you will be asked to install it next time you try to run that script. ```sh ❯ codama run my-script ▲ Your script requires additional dependencies. ▲ Install command: pnpm install my-external-visitor ? Install dependencies? › (Y/n) ``` You can [learn more about the Codama CLI here](/packages/cli/README.md). ## Available visitors The tables below aim to help you discover visitors from the Codama ecosystem that you can use in your scripts. Feel free to PR your own visitor here for others to discover. Note that they are ordered alphabetically. ### Generates documentation | Visitor | Description | Maintainer | | ------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ---------- | | `@codama/renderers-demo` ([docs](https://github.com/codama-idl/renderers-demo)) | Generates simple documentation as a template to help others create new visitors. | Codama | ### Generates program clients | Visitor | Description | Maintainer | | ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | --------------------------------------------- | | `@codama/renderers-go` ([docs](https://github.com/codama-idl/renderers-go)) | Generates a Go client compatible with [the Solana Go SDK](https://github.com/gagliardetto/solana-go). | [Sonic](hhttps://github.com/sonicfromnewyoke) | | `@codama/renderers-js` ([docs](https://github.com/codama-idl/renderers-js)) | Generates a JavaScript client compatible with [Solana Kit](https://www.solanakit.com/). | [Anza](https://www.anza.xyz/) | | `@codama/renderers-js-umi` ([docs](https://github.com/codama-idl/renderers-js-umi)) | Generates a JavaScript client compatible with [the Umi framework](https://developers.metaplex.com/umi). | [Metaplex](https://www.metaplex.com/) | | `@codama/renderers-rust` ([docs](https://github.com/codama-idl/renderers-rust)) | Generates a Rust client compatible with [the Solana SDK](https://github.com/anza-xyz/solana-sdk). | [Anza](https://www.anza.xyz/) | | `@codama/renderers-vixen-parser` ([docs](https://github.com/codama-idl/renderers-vixen-parser)) | Generates [Yellowstone](https://github.com/rpcpool/yellowstone-grpc) account and instruction parsers. | [Triton One](https://triton.one/) | | `@limechain/codama-dart` ([docs](https://github.com/limechain/codama-dart)) | Generates a Dart client. | [LimeChain](https://github.com/limechain/) | | `codama-py` ([docs](https://github.com/Solana-ZH/codama-py)) | Generates a Python client. | [Solar](https://github.com/Solana-ZH) | ### Provides utility | Visitor | Description | Maintainer | | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | | `@codama/visitors#*` ([docs](https://github.com/codama-idl/codama/blob/main/packages/visitors/README.md)) | Provides a big library of utility visitors that can be used to manipulate Codama IDLs. For instance, `updateErrorsVisitor` can be used to update error messages in your IDL . [Check out the docs](https://github.com/codama-idl/codama/blob/main/packages/visitors/README.md) to see all available visitors. | Codama | | `@codama/visitors-core#*` ([docs](https://github.com/codama-idl/codama/blob/main/packages/visitors-core/README.md)) | Everything included in `visitors-core` is also included in `visitors`. The helpers offered in this package are slightly more advanced and can be used to help you [build your own visitors](https://github.com/codama-idl/codama/blob/main/packages/visitors-core/README.md#writing-your-own-visitor). | Codama | ## Getting a Codama IDL We are currently working on a set of transparent macros that can be added to any program in order to extract a Codama IDL from it. There are still a lot more macros and scenarios for us to support but most programs can already benefit from these macros. You can then extract an IDL from the provided crate path using the Codama API like so: ```rust use codama::Codama; let codama = Codama::load(crate_path)?; let idl_json = codama.get_json_idl()?; ``` We will add documentation on Codama macros when they are fully implemented but feel free to check this example that extract a Codama IDL from the [System program interface](https://github.com/lorisleiva/codama-demo-2025-08/tree/main/3-from-macros/program/src) using a [build script](https://github.com/lorisleiva/codama-demo-2025-08/blob/main/3-from-macros/program/build.rs). ## Codama's architecture The Codama IDL is designed as a tree of nodes starting with the `RootNode` which contains a `ProgramNode` and additional data such as the Codama version used when the IDL was created. Codama provides over 60 different types of nodes that help describe nearly every aspect of your Solana programs. [You can read more about the Codama nodes here](./packages/nodes). ![A small example of a Codama IDL as a tree of nodes. It starts with a RootNode and goes down to ProgramNode, AccountNode, InstructionNode, etc.](https://github.com/codama-idl/codama/assets/3642397/9d53485d-a4f6-459a-b7eb-58faab716bc1) Because everything is designed as a `Node`, we can transform the IDL, aggregate information, and output various utility tools using special objects that can traverse node trees known as visitors. [See this documentation to learn more about Codama visitors](./packages/visitors-core). ![A small example of how a visitor can transform a Codama IDL into another Codama IDL. This example illustrates the "deleteNodesVisitor" which recursively removes NumberTypeNodes from a tree of nested TypleTypeNodes.](https://github.com/codama-idl/codama/assets/3642397/f54e83d1-eade-4674-80dc-7ddc360f5f66) ## Other resources - [Solana Stack Exchange](https://solana.stackexchange.com/questions/tagged/codama). - Working with Anchor - [Anchor and Solana Kit tutorial](https://www.youtube.com/watch?v=2T3DOMv7iR4). - [Anchor Election app](https://github.com/quiknode-labs/anchor-election-2025). - [Anchor Swap/Escrow app](https://github.com/quiknode-labs/you-will-build-a-solana-program). ================================================ FILE: eslint.config.mjs ================================================ import solanaConfig from '@solana/eslint-config-solana'; import { defineConfig } from 'eslint/config'; export default defineConfig([ { ignores: ['**/dist/**', '**/e2e/**', '**/generated/**', '**/target/**'], }, { files: ['**/*.ts', '**/*.(c|m)?js'], extends: [solanaConfig], }, { files: ['packages/cli/**', 'packages/nodes/**', 'packages/node-types/**'], rules: { 'sort-keys-fix/sort-keys-fix': 'off', 'typescript-sort-keys/interface': 'off', }, }, ]); ================================================ FILE: package.json ================================================ { "name": "codama-monorepo", "private": true, "scripts": { "build": "turbo run build --log-order grouped", "lint": "turbo run lint --log-order grouped", "lint:fix": "turbo lint:fix --log-order grouped && pnpm prettier --ignore-unknown --write '{.,!packages}/*'", "test": "turbo run test --log-order grouped", "publish-packages": "pnpm build && changeset publish" }, "devDependencies": { "@changesets/changelog-github": "^0.5.2", "@changesets/cli": "^2.29.8", "@solana/eslint-config-solana": "^5.0.0", "@solana/prettier-config-solana": "0.0.6", "@types/node": "^25", "agadoo": "^3.0.0", "browserslist-to-esbuild": "^2.1.1", "eslint": "^9.39.2", "happy-dom": "^20.1.0", "prettier": "^3.7.4", "rimraf": "6.1.2", "tsup": "^8.5.1", "turbo": "^2.7.4", "typescript": "^5.9.3", "vitest": "^4.0.16" }, "engines": { "node": ">=20.18.0" }, "packageManager": "pnpm@10.15.1", "prettier": "@solana/prettier-config-solana" } ================================================ FILE: packages/cli/.gitignore ================================================ dist/ ================================================ FILE: packages/cli/.prettierignore ================================================ dist/ test/e2e/ test-ledger/ target/ CHANGELOG.md ================================================ FILE: packages/cli/LICENSE ================================================ MIT License Copyright (c) 2025 Codama Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: packages/cli/README.md ================================================ # Codama ➤ CLI [![npm][npm-image]][npm-url] [![npm-downloads][npm-downloads-image]][npm-url] [npm-downloads-image]: https://img.shields.io/npm/dm/@codama/cli.svg?style=flat [npm-image]: https://img.shields.io/npm/v/@codama/cli.svg?style=flat&label=%40codama%2Fcli [npm-url]: https://www.npmjs.com/package/@codama/cli This package provides a CLI for the Codama library that can be used to run scripts on Codama IDLs. Note that, whilst the CLI code is located in the `@codama/cli` package, the CLI binary is also included in the main `codama` library. ## Installation Once you have the `codama` package installed, you can use the CLI using the `codama` binary. ```sh pnpm install codama codama --help ``` Note that you may install it from `@codama/cli` instead if you only want the CLI without the rest of the Codama library. ## Commands ### `codama init` To get started with the Codama CLI, you will first need to create a [Codama configuration file](#configuration-file). You can do this using the `init` command as follows: ```sh codama init ``` You will be prompted for the path of your IDL and asked to select any script presets you would like to use. Here are the available options for the `init` command: | Option | Description | | ----------------- | --------------------------------------------------------------------------------------------------------- | | `[output]` | As an optional argument, you may provide the path used to output the configuration file. | | `--default`, `-d` | Skips all prompts and uses the default values. | | `--force` | Overwrites any existing configuration file. | | `--gill` | Initializes a configuration file for a [gill based Codama](https://gill.site/docs/guides/codama) project. | | `--js` | Generates a JavaScript configuration file instead of a JSON one. | ### `codama run` Once you have a configuration file, you can run your Codama scripts using the `codama run` command as follows: ```sh codama run # Only runs your before visitors, no scripts. codama run js rust # Runs your before visitors followed by the `js` and `rust` scripts. codama run --all # Runs your before visitors followed by all your scripts. ``` Here are the available options for the `run` command: | Option | Description | | ----------------------- | ---------------------------------------------------------------------------------------- | | `[scripts...]` | As optional arguments, you may provide the names of the scripts you wish to run. | | `--all`, `-a` | Runs all the scripts defined in your configuration file. | | `--config `, `-c` | Specifies the path to your configuration file. Defaults to `codama.json` or `codama.js`. | | `--idl`, `-i` | Overrides the `idl` field in your configuration file. | ## Configuration file > [!NOTE] > If you don't have a Codama configuration file yet, you can generate a new one using the `codama init` command as [described above](#codama-init). The Codama configuration file defines an object containing the following fields: - `idl` (string): The path to the IDL file. This can be a Codama IDL or an Anchor IDL which will be automatically converted to a Codama IDL. ```json { "idl": "path/to/idl" } ``` - `before` (array): An array of visitors that will run before every script. See [the next section](#using-visitors) for more details on how to use visitors in your configuration file. ```json { "before": ["./my-visitor.js", "external-library#someVisitor"] } ``` - `scripts` (object): An object defining the available Codama scripts. The keys identify the scripts and the values are arrays of visitors that make up the script. ```json { "scripts": { "apple": ["./my-apple-visitor.js"], "banana": ["./my-banana-visitor.js"] } } ``` Whether it is in the `before` array or in the `scripts` values, if you have a single visitor, you may provide it directly instead of wrapping it in an array. For instance, the following configuration file is valid: ```json { "idl": "path/to/idl", "before": "./my-visitor.js", "scripts": { "apple": "./my-apple-visitor.js" } } ``` Note that the configuration file can also be a JavaScript file exporting the configuration object as the `default` export. ```js export default { idl: 'path/to/idl', before: './my-visitor.js', scripts: { apple: './my-apple-visitor.js' }, }; ``` ## Using visitors When using a visitor in your configuration file, **you must provide its import path**. This can either be a local path (relative or absolute) or an external NPM package. For instance the following are all valid visitor import paths: ```js './my-visitor.js'; // Relative local path. '/Users/me/my-visitor.js'; // Absolute local path. 'some-library'; // External package. '@acme/some-library'; // Scoped external package. ``` In all these cases, the visitor will be imported from the `default` export of the module by default. If you want to **import a named export** instead, you may append a `#` followed by the export name to the import path. For instance: ```js './my-visitor.js#myExport'; // Named export from a local path. '@acme/some-library#myExport'; // Named export from an external package. ``` Some visitors may instead be **exported as functions** that return visitor objects. This allows the visitor to receive arguments from the end-user to customize its behavior. When that is the case, you may instead define your visitor as an object with the following fields: - `from` (string): The import path (and potentially the export name) of the visitor. - `args` (array): An array of arguments to pass to the visitor. If you don't need to pass any arguments to the visitor function, you may simply provide the import path as a string instead of an object. ```json { "from": "@acme/some-library#myExport", "args": ["hello", { "someOption": true }] } ``` Finally note that, if the invoked visitor returns a new `RootNode`, this new `RootNode` will be used for the subsequent visitors instead of the original one. This allows us to chain visitors that modify the Codama IDL. Consider the following example such that the `./delete-all-accounts.js` visitor returns a new IDL with all accounts removed it. ```js export default { scripts: { documentation: [ './delete-all-accounts.js', // After this visitor, the IDL has no accounts. './generate-documentation.js', // Generates documentation for an IDL with no accounts. ], }, }; ``` ## Recipes There are plenty of existing visitors that you can use in your Codama scripts. The "[Available visitors](https://github.com/codama-idl/codama?tab=readme-ov-file#available-visitors)" section of the Codama README aims to list as many of them as possible. This includes visitors maintained by various teams across the ecosystem. The examples below show how to use some of these visitors in your configuration file. They make heavy use of the [`@codama/visitors`](https://github.com/codama-idl/codama/tree/main/packages/visitors/README.md) package which provides a large number of utility visitors. ### Deleting nodes Returns a new IDL with the specified nodes removed. See [`deleteNodesVisitor`](https://github.com/codama-idl/codama/tree/main/packages/visitors-core#deletenodesvisitor) and [node selectors](https://github.com/codama-idl/codama/tree/main/packages/visitors-core#selecting-nodes). In the example below, we remove the `mint` account, the `initializeMint` instruction and all errors from the IDL. ```json { "from": "@codama/visitors#deleteNodesVisitor", "args": [["[accountNode]mint", "[instructionNode]initializeMint", "[errorNode]"]] } ``` ### Generating a JavaScript client Generates a JavaScript client for the IDL at the specified output path. See [`@codama/renderer-js`](https://github.com/codama-idl/renderers-js). ```json { "from": "@codama/renderers-js", "args": ["clients/js/src/generated"] } ``` ### Removing documentation Returns a new IDL with documentation removed from all nodes. See [`removeDocsVisitor`](https://github.com/codama-idl/codama/tree/main/packages/visitors-core#removedocsvisitor) ```json "@codama/visitors#removeDocsVisitor" ``` ### Unwrapping linked types Returns a new IDL with specified type links replaced by their underlying types. See [`unwrapDefinedTypesVisitor`](https://github.com/codama-idl/codama/tree/main/packages/visitors#unwrapDefinedTypesVisitor) In the example below, any links to the `counter` or `escrow` types will be replaced by the actual definitions of these types. ```json { "from": "@codama/visitors#unwrapDefinedTypesVisitor", "args": [["counter", "escrow"]] } ``` ### Updating accounts Returns a new IDL with updated account information. See [`updateAccountsVisitor`](https://github.com/codama-idl/codama/tree/main/packages/visitors#updateAccountsVisitor) In the example below, we rename the `vault` account to `safe` and update the `authority` field of the `bank` account to `treasury`. ```json { "from": "@codama/visitors#updateAccountsVisitor", "args": [ { "vault": { "name": "safe" }, "bank": { "data": { "authority": "treasury" } } } ] } ``` ================================================ FILE: packages/cli/bin/cli.cjs ================================================ #!/usr/bin/env -S node const run = require('../dist/cli.cjs').run; run(process.argv); ================================================ FILE: packages/cli/package.json ================================================ { "name": "@codama/cli", "version": "1.5.1", "description": "A CLI for setting up and managing Codama IDLs", "exports": { "types": "./dist/types/index.d.ts", "node": { "import": "./dist/index.node.mjs", "require": "./dist/index.node.cjs" } }, "main": "./dist/index.node.cjs", "module": "./dist/index.node.mjs", "types": "./dist/types/index.d.ts", "type": "commonjs", "bin": { "codama": "./bin/cli.cjs" }, "files": [ "./bin", "./dist/types", "./dist/cli.*", "./dist/index.*" ], "sideEffects": false, "keywords": [ "codama", "standard", "cli" ], "scripts": { "build": "rimraf dist && tsup && tsc -p ./tsconfig.declarations.json", "dev": "vitest --project node", "lint": "eslint . && prettier --check .", "lint:fix": "eslint --fix . && prettier --write .", "test": "pnpm test:types && pnpm test:treeshakability && pnpm test:unit && pnpm test:exports", "test:exports": "node test/exports/module.mjs && node test/exports/commonjs.cjs", "test:treeshakability": "for file in dist/index.*.mjs; do agadoo $file; done", "test:types": "tsc --noEmit", "test:unit": "vitest run" }, "dependencies": { "@codama/nodes": "workspace:*", "@codama/visitors": "workspace:*", "@codama/visitors-core": "workspace:*", "commander": "^14.0.2", "picocolors": "^1.1.1", "prompts": "^2.4.2" }, "devDependencies": { "@types/prompts": "^2.4.9" }, "license": "MIT", "repository": { "type": "git", "url": "https://github.com/codama-idl/codama" }, "bugs": { "url": "http://github.com/codama-idl/codama/issues" }, "browserslist": [ "supports bigint and not dead", "maintained node versions" ] } ================================================ FILE: packages/cli/src/cli/index.ts ================================================ import { createProgram, runProgram } from '../program'; const program = createProgram(); export async function run(argv: readonly string[]) { await runProgram(program, argv); } ================================================ FILE: packages/cli/src/commands/convert.ts ================================================ import { Command } from 'commander'; import { getRootNodeFromIdl, readJson, writeFile } from '../utils'; export function setConvertCommand(program: Command): void { program .command('convert') .argument('', 'Path to the input IDL file (e.g., Anchor or supported standard)') .argument('', 'Path for the output Codama IDL file') .description('Convert a supported IDL file to Codama IDL format') .action(doConvert); } async function doConvert(idlPath: string, outPath: string) { const idl = await readJson(idlPath); const node = await getRootNodeFromIdl(idl); await writeFile(outPath, JSON.stringify(node, null, 2)); console.log(`Converted IDL written to ${outPath}`); } ================================================ FILE: packages/cli/src/commands/index.ts ================================================ export * from './init'; export * from './run'; export * from './convert'; ================================================ FILE: packages/cli/src/commands/init.ts ================================================ import { Command } from 'commander'; import pico from 'picocolors'; import prompts, { PromptType } from 'prompts'; import { Config, ScriptConfig, ScriptName } from '../config'; import { canRead, CliError, importModuleItem, installMissingDependencies, isRootNode, logBanner, logSuccess, PROMPT_OPTIONS, resolveRelativePath, writeFile, } from '../utils'; export function setInitCommand(program: Command): void { program .command('init') .argument('[output]', 'Optional path used to output the configuration file') .option('-d, --default', 'Bypass prompts and select all defaults options') .option('--force', 'Overwrite existing configuration file, if any') .option('--js', 'Forces the output to be a JavaScript file') .option('--gill', 'Forces the output to be a gill based JavaScript file') .action(doInit); } type InitOptions = { default?: boolean; force?: boolean; gill?: boolean; js?: boolean; }; async function doInit(explicitOutput: string | undefined, options: InitOptions) { const output = getOutputPath(explicitOutput, options); const configFileType = getConfigFileType(output, options); if (!options.force && (await canRead(output))) { throw new CliError(`Configuration file already exists.`, [`${pico.bold('Path')}: ${output}`]); } // Start prompts. logBanner(); const result = await getPromptResult(options, configFileType); // Check dependencies. const isAnchor = await isAnchorIdl(result.idlPath); await installMissingDependencies(`Your configuration requires additional dependencies.`, [ ...(isAnchor ? ['@codama/nodes-from-anchor'] : []), ...(result.scripts.includes('js') ? ['@codama/renderers-js'] : []), ...(result.scripts.includes('rust') ? ['@codama/renderers-rust'] : []), ]); // Write configuration file. const content = getContentFromPromptResult(result, configFileType); await writeFile(output, content); console.log(); logSuccess(pico.bold('Configuration file created.'), [`${pico.bold('Path')}: ${output}`]); } function getOutputPath(explicitOutput: string | undefined, options: Pick): string { if (explicitOutput) { return resolveRelativePath(explicitOutput); } return resolveRelativePath(options.js || options.gill ? 'codama.js' : 'codama.json'); } type PromptResult = { idlPath: string; jsPath?: string; rustPath?: string; scripts: string[]; }; async function getPromptResult( options: Pick, configFileType: ConfigFileType, ): Promise { const defaults = getDefaultPromptResult(); if (options.default) { return defaults; } const hasScript = (script: string, type: PromptType = 'text') => (_: unknown, values: { scripts: string[] }) => values.scripts.includes(script) ? type : null; return await prompts( [ { initial: defaults.idlPath, message: 'Where is your IDL located? (Supports Codama and Anchor IDLs).', name: 'idlPath', type: 'text', }, { choices: [ { selected: true, title: 'Generate JavaScript client', value: 'js' }, { selected: true, title: 'Generate Rust client', value: 'rust' }, ], instructions: '[space] to toggle / [a] to toggle all / [enter] to submit', message: 'Which script preset would you like to use?', name: 'scripts', type: 'multiselect', onRender() { if (configFileType === 'gill') { const value = (this as unknown as { value: prompts.Choice[] }).value; const jsChoice = value.find(choice => choice.value === 'js')!; jsChoice.description = pico.yellow('Required with --gill option.'); jsChoice.selected = true; } }, }, { initial: defaults.jsPath, message: '[js] Where is the JavaScript client package located?', name: 'jsPath', type: hasScript('js'), }, { initial: defaults.rustPath, message: '[rust] Where is the Rust client crate located?', name: 'rustPath', type: hasScript('rust'), }, ], PROMPT_OPTIONS, ); } function getDefaultPromptResult(): PromptResult { return { idlPath: 'program/idl.json', jsPath: 'clients/js', rustPath: 'clients/rust', scripts: ['js', 'rust'], }; } type ConfigFileType = 'gill' | 'js' | 'json'; function getConfigFileType(output: string, options: Pick): ConfigFileType { if (options.gill) return 'gill'; else if (options.js) return 'js'; return output.endsWith('.js') ? 'js' : 'json'; } function getContentFromPromptResult(result: PromptResult, configFileType: ConfigFileType): string { switch (configFileType) { case 'gill': return getContentForGill(result); case 'js': return ( `export default ` + JSON.stringify(getConfigFromPromptResult(result), null, 4) // Remove quotes around property names .replace(/"([^"]+)":/g, '$1:') // Convert double-quoted strings to single quotes .replace(/"([^"]*)"/g, "'$1'") ); case 'json': default: return JSON.stringify(getConfigFromPromptResult(result), null, 4); } } function getConfigFromPromptResult(result: PromptResult): Config { const scripts: Record = {}; if (result.scripts.includes('js')) { scripts.js = { from: '@codama/renderers-js', args: [result.jsPath], }; } if (result.scripts.includes('rust')) { scripts.rust = { from: '@codama/renderers-rust', args: [result.rustPath, { formatCode: true }], }; } return { idl: result.idlPath, before: [], scripts }; } function getContentForGill(result: PromptResult): string { const attributes: string[] = [ `idl: "${result.idlPath}"`, `clientJs: "${result.jsPath}"`, ...(result.scripts.includes('rust') ? [`clientRust: "${result.rustPath}"`] : []), ]; const attributesString = attributes.map(attr => ` ${attr},\n`).join(''); return ( `import { createCodamaConfig } from "gill";\n\n` + `export default createCodamaConfig({\n${attributesString}});\n` ); } async function isAnchorIdl(idlPath: string): Promise { const resolvedIdlPath = resolveRelativePath(idlPath); if (!(await canRead(resolvedIdlPath))) return false; try { const idlContent = await importModuleItem({ identifier: 'IDL', from: resolvedIdlPath }); return !isRootNode(idlContent); } catch { return false; } } ================================================ FILE: packages/cli/src/commands/run.ts ================================================ import type { RootNode } from '@codama/nodes'; import { visit, type Visitor } from '@codama/visitors-core'; import { Command } from 'commander'; import pico from 'picocolors'; import { ScriptName } from '../config'; import { getParsedConfigFromCommand, ParsedConfig } from '../parsedConfig'; import { CliError, getRootNodeVisitors, installMissingDependencies, isLocalModulePath, logInfo, logSuccess, logWarning, } from '../utils'; export function setRunCommand(program: Command): void { program .command('run') .argument('[scripts...]', 'The scripts to execute') .option('-a, --all', 'Run all scripts in the configuration file') .action(doRun); } type RunOptions = { all?: boolean; }; async function doRun(explicitScripts: string[], { all }: RunOptions, cmd: Command) { if (all && explicitScripts.length > 0) { logWarning(`CLI arguments "${explicitScripts.join(' ')}" are ignored because the "--all" option is set.`); } const parsedConfig = await getParsedConfigFromCommand(cmd); const scripts = all ? Object.keys(parsedConfig.scripts) : explicitScripts; const plans = await getPlans(parsedConfig, scripts); runPlans(plans, parsedConfig.rootNode); } type RunPlan = { script: ScriptName | null; visitors: Visitor[]; }; async function getPlans( parsedConfig: Pick, scripts: ScriptName[], ): Promise { const plans: RunPlan[] = []; if (scripts.length === 0 && parsedConfig.before.length === 0) { throw new CliError('There are no scripts or before visitors to run.'); } checkMissingScripts(parsedConfig, scripts); await checkMissingDependencies(parsedConfig, scripts); if (parsedConfig.before.length > 0) { plans.push({ script: null, visitors: await getRootNodeVisitors(parsedConfig.before) }); } for (const script of scripts) { plans.push({ script, visitors: await getRootNodeVisitors(parsedConfig.scripts[script]) }); } return plans; } function runPlans(plans: RunPlan[], rootNode: RootNode): void { for (const plan of plans) { const result = runPlan(plan, rootNode); if (!plan.script) { rootNode = result; } } } function runPlan(plan: RunPlan, rootNode: RootNode): RootNode { const visitorLength = plan.visitors.length; const visitorPluralized = visitorLength === 1 ? 'visitor' : 'visitors'; const identifier = plan.script ? `script "${plan.script}" with ${visitorLength} ${visitorPluralized}` : `${visitorLength} before ${visitorPluralized}`; logInfo(`Running ${identifier}...`); const newRoot = plan.visitors.reduce(visit, rootNode); logSuccess(`Executed ${identifier}!`); return newRoot; } function checkMissingScripts(parsedConfig: Pick, scripts: ScriptName[]) { const missingScripts = scripts.filter(script => !parsedConfig.scripts[script]); if (missingScripts.length === 0) return; const scriptPluralized = missingScripts.length === 1 ? 'Script' : 'Scripts'; const message = parsedConfig.configPath ? `${scriptPluralized} not found in configuration file.` : `${scriptPluralized} not found because no configuration file was found.`; const items = [ `${pico.bold(scriptPluralized)}: ${missingScripts.join(', ')}`, ...(parsedConfig.configPath ? [`${pico.bold('Path')}: ${parsedConfig.configPath}`] : []), ]; throw new CliError(message, items); } async function checkMissingDependencies( parsedConfig: Pick, scripts: ScriptName[], ) { const dependencies = new Set([ ...parsedConfig.before.map(v => v.path), ...scripts.flatMap(script => parsedConfig.scripts[script]?.map(v => v.path) ?? []), ]); const externalDependencies = [...dependencies].filter(dep => !isLocalModulePath(dep)); const scriptsRequirePluralized = scripts.length === 1 ? 'script requires' : 'scripts require'; const installed = await installMissingDependencies( `Your ${scriptsRequirePluralized} additional dependencies.`, externalDependencies, ); if (!installed) { throw new CliError('Cannot proceed without missing dependencies.'); } } ================================================ FILE: packages/cli/src/config.ts ================================================ import path from 'node:path'; import pico from 'picocolors'; import { ProgramOptions } from './programOptions'; import { canRead, CliError, importModuleItem, logWarning } from './utils'; export type Config = Readonly<{ idl?: string; scripts?: ScriptsConfig; before?: readonly VisitorConfig[]; }>; export type ScriptName = string; export type ScriptConfig = VisitorConfig | readonly VisitorConfig[]; export type ScriptsConfig = Readonly>; export type VisitorPath = string; export type VisitorConfig = VisitorConfigObject | VisitorPath; export type VisitorConfigObject = Readonly<{ args?: T; from: VisitorPath; }>; export async function getConfig(options: Pick): Promise<[Config, string | null]> { const configPath = options.config != null ? path.resolve(options.config) : await getDefaultConfigPath(); if (!configPath) { logWarning('No configuration file found. Using empty configs. Make sure you provide the `--idl` option.'); return [{}, configPath]; } const configFile = await importModuleItem({ identifier: 'configuration file', from: configPath }); if (!configFile || typeof configFile !== 'object') { throw new CliError(`Invalid configuration file.`, [`${pico.bold('Path')}: ${configPath}`]); } return [configFile, configPath]; } async function getDefaultConfigPath(): Promise { const candidatePaths = ['codama.js', 'codama.mjs', 'codama.cjs', 'codama.json']; for (const candidatePath of candidatePaths) { const resolvedPath = path.resolve(process.cwd(), candidatePath); if (await canRead(resolvedPath)) { return resolvedPath; } } return null; } ================================================ FILE: packages/cli/src/index.ts ================================================ export * from './program'; ================================================ FILE: packages/cli/src/parsedConfig.ts ================================================ import type { RootNode } from '@codama/nodes'; import { Command } from 'commander'; import { Config, getConfig, ScriptName, ScriptsConfig, VisitorConfig, VisitorPath } from './config'; import { ProgramOptions } from './programOptions'; import { CliError, getRootNodeFromIdl, importModuleItem, isLocalModulePath, resolveConfigPath, resolveRelativePath, } from './utils'; export type ParsedConfig = Readonly<{ configPath: string | null; idlContent: unknown; idlPath: string; rootNode: RootNode; scripts: ParsedScriptsConfig; before: readonly ParsedVisitorConfig[]; }>; export type ParsedScriptsConfig = Readonly>; export type ParsedVisitorConfig = Readonly<{ args: T; index: number; item: string | undefined; path: VisitorPath; script: ScriptName | null; }>; export async function getParsedConfigFromCommand(cmd: Command): Promise { return await getParsedConfig(cmd.optsWithGlobals()); } export async function getParsedConfig(options: Pick): Promise { const [config, configPath] = await getConfig(options); return await parseConfig(config, configPath, options); } async function parseConfig( config: Config, configPath: string | null, options: Pick, ): Promise { const idlPath = parseIdlPath(config, configPath, options); const idlContent = await importModuleItem({ identifier: 'IDL', from: idlPath }); const rootNode = await getRootNodeFromIdl(idlContent); const scripts = parseScripts(config.scripts ?? {}, configPath); const visitors = (config.before ?? []).map((v, i) => parseVisitorConfig(v, configPath, i, null)); return { configPath, idlContent, idlPath, rootNode, scripts, before: visitors }; } function parseIdlPath( config: Pick, configPath: string | null, options: Pick, ): string { if (options.idl) { return resolveRelativePath(options.idl); } if (config.idl) { return resolveConfigPath(config.idl, configPath); } throw new CliError('No IDL identified. Please provide the `--idl` option or set it in the configuration file.'); } function parseScripts(scripts: ScriptsConfig, configPath: string | null): ParsedScriptsConfig { const entryPromises = Object.entries(scripts).map(([name, scriptConfig]) => { const visitors: readonly VisitorConfig[] = Array.isArray(scriptConfig) ? scriptConfig : [scriptConfig]; return [name, visitors.map((v, i) => parseVisitorConfig(v, configPath, i, name))] as const; }); return Object.fromEntries(entryPromises); } function parseVisitorConfig( visitorConfig: VisitorConfig, configPath: string | null, index: number, script: ScriptName | null, ): ParsedVisitorConfig { const emptyArgs = [] as readonly unknown[] as T; const visitorPath = typeof visitorConfig === 'string' ? visitorConfig : visitorConfig.from; const visitorArgs = typeof visitorConfig === 'string' ? emptyArgs : (visitorConfig.args ?? emptyArgs); const [path, item] = resolveVisitorPath(visitorPath, configPath); return { args: visitorArgs, index, item, path, script }; } function resolveVisitorPath(visitorPath: string, configPath: string | null): readonly [string, string | undefined] { const [modulePath, itemName] = visitorPath.split('#') as [string, string | undefined]; const resolveModulePath = isLocalModulePath(modulePath) ? resolveConfigPath(modulePath, configPath) : modulePath; return [resolveModulePath, itemName]; } ================================================ FILE: packages/cli/src/program.ts ================================================ import { Command, createCommand, ParseOptions } from 'commander'; import pico from 'picocolors'; import { setConvertCommand, setInitCommand, setRunCommand } from './commands'; import { setProgramOptions } from './programOptions'; import { logDebug, logError } from './utils'; export async function codama(args: string[], opts?: { suppressOutput?: boolean }): Promise { const program = createProgram({ exitOverride: true, suppressOutput: opts?.suppressOutput, }); await runProgram(program, args, { from: 'user' }); } export async function runProgram(program: Command, argv: readonly string[], parseOptions?: ParseOptions) { try { await program.parseAsync(argv, parseOptions); } catch (err) { const error = err as { message: string; stack?: string; items?: string[] }; if (program.opts().debug) { logDebug(`${error.stack}`); } logError(pico.bold(error.message), error.items ?? []); process.exitCode = 1; } } export function createProgram(internalOptions?: { exitOverride?: boolean; suppressOutput?: boolean }): Command { const program = createCommand() .version(__VERSION__) .allowExcessArguments(false) .configureHelp({ showGlobalOptions: true, sortOptions: true, sortSubcommands: true }); // Set program options and commands. setProgramOptions(program); setInitCommand(program); setRunCommand(program); setConvertCommand(program); // Internal options. if (internalOptions?.exitOverride) { program.exitOverride(); } if (internalOptions?.suppressOutput) { program.configureOutput({ writeErr: () => {}, writeOut: () => {}, }); } return program; } ================================================ FILE: packages/cli/src/programOptions.ts ================================================ import { Command } from 'commander'; export type ProgramOptions = Readonly<{ config?: string; debug?: boolean; idl?: string; }>; export function setProgramOptions(program: Command): void { program .option('--debug', 'include debugging information, such as stack dump') .option('-i, --idl ', 'The path to the IDL to use.') .option('-c, --config ', 'The path to the Codama configuration file. Defaults to `codama.(js|json)`.'); } ================================================ FILE: packages/cli/src/types/global.d.ts ================================================ declare const __BROWSER__: boolean; declare const __ESM__: boolean; declare const __NODEJS__: boolean; declare const __REACTNATIVE__: boolean; declare const __TEST__: boolean; declare const __VERSION__: string; ================================================ FILE: packages/cli/src/utils/childCommands.ts ================================================ import { ChildProcess, spawn, SpawnOptions } from 'child_process'; export type ChildCommand = { command: string; args: string[]; }; export function createChildCommand(command: string, args: string[] = []): ChildCommand { return { command, args }; } export function formatChildCommand(childCommand: ChildCommand): string { const { command, args } = childCommand; return [command, ...args].join(' '); } export type ChildProcessResult = ChildProcess & { stdoutString: string; stderrString: string; }; export type ChildProcessError = Error & { childProcess: ChildProcessResult; }; export async function spawnChildCommand( childCommand: ChildCommand, options: SpawnOptions & { quiet: boolean } = { quiet: false }, ): Promise { const { command, args } = childCommand; const childProcess = spawn(command, args, options) as ChildProcessResult; childProcess.stdoutString = ''; childProcess.stderrString = ''; childProcess.stdout?.on('data', (chunk: Uint8Array) => { childProcess.stdoutString += chunk.toString(); if (!options.quiet) { process.stdout.write(chunk); } }); childProcess.stderr?.on('data', (chunk: Uint8Array) => { childProcess.stderrString += chunk.toString(); if (!options.quiet) { process.stderr.write(chunk); } }); const exitCode: number = await new Promise((resolve, reject) => { childProcess.on('error', () => reject(createChildProcessResultError(childCommand, childProcess))); childProcess.on('close', resolve); }); if (exitCode) { throw createChildProcessResultError(childCommand, childProcess); } return childProcess; } function createChildProcessResultError( childCommand: ChildCommand, childProcess: ChildProcessResult, ): ChildProcessError { const error = new Error(`Command [${formatChildCommand(childCommand)}] failed`) as ChildProcessError; error.childProcess = childProcess; return error; } ================================================ FILE: packages/cli/src/utils/errors.ts ================================================ export class CliError extends Error { constructor( message: string, public items: string[] = [], options?: ErrorOptions, ) { super(message, options); this.name = 'CliError'; } } ================================================ FILE: packages/cli/src/utils/fs.ts ================================================ import { R_OK, W_OK } from 'node:constants'; import fs, { PathLike } from 'node:fs'; import path from 'node:path'; export function resolveRelativePath(childPath: string, relativeDirectory: string | null = null) { return path.resolve(relativeDirectory ?? process.cwd(), childPath); } export function resolveConfigPath(childPath: string, configPath: string | null) { const configDir = configPath ? path.dirname(configPath) : null; return resolveRelativePath(childPath, configDir); } export function isLocalModulePath(modulePath: string) { return modulePath.startsWith('.') || modulePath.startsWith('/'); } export async function readJson(filePath: string): Promise { return JSON.parse(await readFile(filePath)) as T; } export async function readFile(filePath: string): Promise { return await fs.promises.readFile(filePath, 'utf8'); } export async function writeFile(filePath: string, content: string) { const directory = path.dirname(filePath); if (!(await canWrite(directory))) { await fs.promises.mkdir(directory, { recursive: true }); } await fs.promises.writeFile(filePath, content); } export async function canRead(p: PathLike) { try { await fs.promises.access(p, R_OK); return true; } catch { return false; } } export async function canWrite(p: PathLike) { try { await fs.promises.access(p, W_OK); return true; } catch { return false; } } ================================================ FILE: packages/cli/src/utils/import.ts ================================================ import { createRequire } from 'node:module'; import pico from 'picocolors'; import { CliError } from './errors'; import { canRead, isLocalModulePath, resolveRelativePath } from './fs'; type ImportModuleItemOptions = { from: string; identifier?: string; item?: string; }; export async function importModuleItem(options: ImportModuleItemOptions): Promise { const module = await importModule(options); const moduleItem = pickModuleItem(module, options.item) as T | undefined; if (moduleItem === undefined) { const items = getErrorItems(options); throw new CliError(`Failed to load ${options.identifier ?? 'module'}.`, items); } return moduleItem; } type ModuleDefinition = Partial> & { __esModule?: boolean; default?: Partial> & { default?: Partial> }; }; function pickModuleItem(module: ModuleDefinition, item: string = 'default'): unknown { if (item === 'default') { return module.default?.default ?? module.default ?? module; } return module[item] ?? module.default?.[item] ?? module.default?.default?.[item]; } async function importModule(options: ImportModuleItemOptions): Promise { if (isLocalModulePath(options.from)) { return await importLocalModule(options); } try { return await importExternalUserModule(options); } catch { return await importExternalModule(options); } } async function importLocalModule(options: ImportModuleItemOptions): Promise { const { from, identifier } = options; if (!(await canRead(from))) { const items = getErrorItems(options); throw new CliError(`Cannot access ${identifier ?? 'module'}.`, items); } const dotIndex = from.lastIndexOf('.'); const extension = dotIndex === -1 ? undefined : from.slice(dotIndex); const modulePromise = extension === '.json' ? import(from, { with: { type: 'json' } }) : import(from); return await handleImportPromise(modulePromise, options); } async function importExternalModule(options: ImportModuleItemOptions): Promise { return await handleImportPromise(import(options.from), options); } async function importExternalUserModule(options: ImportModuleItemOptions): Promise { const userPackageJsonPath = resolveRelativePath('package.json'); const userRequire = createRequire(userPackageJsonPath); const userFrom = userRequire.resolve(options.from); return await importExternalModule({ ...options, from: userFrom }); } async function handleImportPromise( importPromise: Promise, options: ImportModuleItemOptions, ): Promise { try { return (await importPromise) as T; } catch (cause) { const items = getErrorItems(options, cause); throw new CliError(`Failed to load ${options.identifier ?? 'module'}.`, items, { cause }); } } function getErrorItems(options: ImportModuleItemOptions, cause?: unknown): string[] { const { from, item } = options; const items = [`${pico.bold('Module')}: ${from}`]; if (item) { items.push(`${pico.bold('Item')}: ${item}`); } const hasCause = !!cause && typeof cause === 'object' && 'message' in cause && typeof cause.message === 'string'; if (hasCause) { items.push(`${pico.bold('Caused by')}: ${(cause as { message: string }).message}`); } return items; } ================================================ FILE: packages/cli/src/utils/index.ts ================================================ export * from './childCommands'; export * from './errors'; export * from './fs'; export * from './import'; export * from './logs'; export * from './nodes'; export * from './packageInstall'; export * from './packageJson'; export * from './packageManager'; export * from './promises'; export * from './prompts'; export * from './visitors'; ================================================ FILE: packages/cli/src/utils/logs.ts ================================================ import pico from 'picocolors'; type LogLevel = 'debug' | 'error' | 'info' | 'success' | 'warning'; type LogOptions = { level: LogLevel; message: string; items?: string[]; }; function getLogLevelInfo(logLevel: LogLevel) { const identity = (text: string) => text; const infos: Record string, (text: string) => string]> = { success: ['✔', pico.green, pico.green], info: ['→', pico.blueBright, identity], warning: ['▲', pico.yellow, pico.yellow], error: ['✖', pico.red, pico.red], debug: ['✱', pico.magenta, pico.magenta], }; return { icon: infos[logLevel][0], color: infos[logLevel][1], messageColor: infos[logLevel][2], }; } const logWrapper = (level: LogLevel) => (message: string, items?: string[]) => log({ level, message, items }); export const logSuccess = logWrapper('success'); export const logError = logWrapper('error'); export const logInfo = logWrapper('info'); export const logWarning = logWrapper('warning'); export const logDebug = logWrapper('debug'); function log({ level, message, items }: LogOptions): void { const { icon, color, messageColor } = getLogLevelInfo(level); console.log(color(icon), messageColor(message)); if (items) { logItems(items, color); } } function logItems(items: string[], color?: (text: string) => string): void { const colorFn = color ?? (text => text); items.forEach((item, index) => { const prefix = index === items.length - 1 ? '└─' : '├─'; console.log(' ' + colorFn(prefix), item); }); } export function logBanner(): void { console.log(pico.bold(codamaColor('Welcome to Codama!'))); } function codamaColor(text: string): string { if (!pico.isColorSupported) return text; return `\x1b[38;2;231;171;97m${text}\x1b[0m`; } ================================================ FILE: packages/cli/src/utils/nodes.ts ================================================ import type { RootNode } from '@codama/nodes'; import { CliError } from './errors'; import { importModuleItem } from './import'; import { installMissingDependencies } from './packageInstall'; export async function getRootNodeFromIdl(idl: unknown): Promise { if (typeof idl !== 'object' || idl === null) { throw new CliError('Unexpected IDL content. Expected an object, got ' + typeof idl); } if (isRootNode(idl)) { return idl; } const hasNodesFromAnchor = await installMissingDependencies( 'Anchor IDL detected. Additional dependencies are required to process Anchor IDLs.', ['@codama/nodes-from-anchor'], ); if (!hasNodesFromAnchor) { throw new CliError('Cannot proceed without Anchor IDL support.'); } const rootNodeFromAnchor = await importModuleItem<(idl: unknown) => RootNode>({ from: '@codama/nodes-from-anchor', item: 'rootNodeFromAnchor', }); return rootNodeFromAnchor(idl); } export function isRootNode(value: unknown): value is RootNode { return ( typeof value === 'object' && value !== null && (value as { standard?: string }).standard === 'codama' && (value as { kind?: string }).kind === 'rootNode' ); } ================================================ FILE: packages/cli/src/utils/packageInstall.ts ================================================ import pico from 'picocolors'; import prompts from 'prompts'; import { ChildCommand, createChildCommand, formatChildCommand, spawnChildCommand } from './childCommands'; import { logError, logInfo, logSuccess, logWarning } from './logs'; import { getPackageJsonDependencies } from './packageJson'; import { getPackageManager } from './packageManager'; import { PROMPT_OPTIONS } from './prompts'; export async function getPackageManagerInstallCommand( packages: string[], options: string[] = [], ): Promise { const packageManager = await getPackageManager(); const args = [packageManager === 'yarn' ? 'add' : 'install', ...packages, ...options]; return createChildCommand(packageManager, args); } export async function installMissingDependencies(message: string, requiredDependencies: string[]): Promise { if (requiredDependencies.length === 0) return true; const installedDependencies = await getPackageJsonDependencies({ includeDev: true }); const missingDependencies = requiredDependencies.filter(dep => !installedDependencies.includes(dep)); if (missingDependencies.length === 0) return true; return await installDependencies(message, missingDependencies); } export async function installDependencies(message: string, dependencies: string[]): Promise { if (dependencies.length === 0) return true; const installCommand = await getPackageManagerInstallCommand(dependencies); const formattedInstallCommand = pico.yellow(formatChildCommand(installCommand)); if (process.env.CI) { logWarning(message); logWarning(`Skipping installation in CI environment. Please install manually:`); logWarning(formattedInstallCommand); return false; } logWarning(message); logWarning(`Install command: ${formattedInstallCommand}`); const dependencyResult: { installDependencies: boolean } = await prompts( { initial: true, message: 'Install dependencies?', name: 'installDependencies', type: 'confirm' }, PROMPT_OPTIONS, ); if (!dependencyResult.installDependencies) { logWarning('Skipping installation.'); return false; } try { logInfo(`Installing`, dependencies); await spawnChildCommand(installCommand, { quiet: true }); logSuccess(`Dependencies installed successfully.`); return true; } catch { logError(`Failed to install dependencies. Please try manually:`); logError(formattedInstallCommand); return false; } } ================================================ FILE: packages/cli/src/utils/packageJson.ts ================================================ import pico from 'picocolors'; import { CliError } from './errors'; import { canRead, readJson, resolveRelativePath } from './fs'; type PackageJson = { name: string; dependencies?: Record; devDependencies?: Record; scripts?: Record; packageManager?: string; [key: string]: unknown; }; let packageJson: PackageJson | undefined; export async function getPackageJson(): Promise { if (!packageJson) { const packageJsonPath = resolveRelativePath('package.json'); if (!(await canRead(packageJsonPath))) { throw new CliError('Cannot read package.json.', [`${pico.bold('Path')}: ${packageJsonPath}`]); } packageJson = await readJson(packageJsonPath); } return packageJson; } export async function getPackageJsonDependencies(options: { includeDev?: boolean } = {}): Promise { const packageJson = await getPackageJson(); return [ ...(packageJson.dependencies ? Object.keys(packageJson.dependencies) : []), ...(options.includeDev && packageJson.devDependencies ? Object.keys(packageJson.devDependencies) : []), ]; } ================================================ FILE: packages/cli/src/utils/packageManager.ts ================================================ import { createChildCommand, spawnChildCommand } from './childCommands'; import { canRead, resolveRelativePath } from './fs'; import { getPackageJson } from './packageJson'; type PackageManager = 'bun' | 'npm' | 'pnpm' | 'yarn'; const FALLBACK_PACKAGE_MANAGER: PackageManager = 'npm'; let packageManager: PackageManager | undefined; export async function getPackageManager(): Promise { if (!packageManager) { packageManager = await detectPackageManager(); } return packageManager; } async function detectPackageManager(): Promise { const fromPackageJson = await detectPackageManagerFromPackageJson(); if (fromPackageJson) return fromPackageJson; const fromLockfile = await detectPackageManagerFromLockfile(); if (fromLockfile) return fromLockfile; const fromInstalledCli = await detectPackageManagerFromInstalledCli(); if (fromInstalledCli) return fromInstalledCli; return FALLBACK_PACKAGE_MANAGER; } async function detectPackageManagerFromPackageJson(): Promise { const packageJson = await getPackageJson(); if (!packageJson.packageManager) return undefined; if (packageJson.packageManager.startsWith('npm@')) return 'npm'; if (packageJson.packageManager.startsWith('pnpm@')) return 'pnpm'; if (packageJson.packageManager.startsWith('yarn@')) return 'yarn'; if (packageJson.packageManager.startsWith('bun@')) return 'bun'; return undefined; } async function detectPackageManagerFromLockfile(): Promise { const [isYarn, isPnpm, isBun, isNpm] = await Promise.all([ canRead(resolveRelativePath('yarn.lock')), canRead(resolveRelativePath('pnpm-lock.yaml')), canRead(resolveRelativePath('bun.lockb')), canRead(resolveRelativePath('package-lock.json')), ]); if (isYarn) return 'yarn'; if (isPnpm) return 'pnpm'; if (isBun) return 'bun'; if (isNpm) return 'npm'; return undefined; } async function detectPackageManagerFromInstalledCli(): Promise { const [isPnpm, isYarn, isBun] = await Promise.all([ hasPackageManagerCli('pnpm'), hasPackageManagerCli('yarn'), hasPackageManagerCli('bun'), ]); if (isPnpm) return 'pnpm'; if (isYarn) return 'yarn'; if (isBun) return 'bun'; return undefined; } async function hasPackageManagerCli(packageManager: PackageManager): Promise { return await spawnChildCommand(createChildCommand(packageManager, ['--version']), { quiet: true }) .then(() => true) .catch(() => false); } ================================================ FILE: packages/cli/src/utils/promises.ts ================================================ export function promisify(value: Promise | T): Promise { return Promise.resolve(value); } ================================================ FILE: packages/cli/src/utils/prompts.ts ================================================ import prompts from 'prompts'; import { CliError } from './errors'; export const PROMPT_OPTIONS: prompts.Options = { onCancel: () => { throw new CliError('Operation cancelled.'); }, }; ================================================ FILE: packages/cli/src/utils/visitors.ts ================================================ import type { RootNode } from '@codama/nodes'; import { rootNodeVisitor, visit, type Visitor } from '@codama/visitors-core'; import pico from 'picocolors'; import { ParsedVisitorConfig } from '../parsedConfig'; import { CliError } from './errors'; import { importModuleItem } from './import'; import { isRootNode } from './nodes'; import { promisify } from './promises'; export async function getRootNodeVisitors( visitors: readonly ParsedVisitorConfig[], ): Promise[]> { return await Promise.all(visitors.map(getRootNodeVisitor)); } async function getRootNodeVisitor(visitorConfig: ParsedVisitorConfig): Promise> { const { item, path } = visitorConfig; const identifier = getVisitorIdentifier(visitorConfig); const moduleItem = await importModuleItem({ identifier, from: path, item }); const visitor = await getVisitorFromModuleItem(identifier, moduleItem, visitorConfig); return rootNodeVisitor(root => { const result = visit(root, visitor); return isRootNode(result) ? result : root; }); } type UnknownFunction = (...args: readonly unknown[]) => unknown; async function getVisitorFromModuleItem( identifier: string, moduleItem: unknown, visitorConfig: ParsedVisitorConfig, ): Promise> { const { args, item, path } = visitorConfig; if (isRootNodeVisitor(moduleItem)) { return moduleItem; } if (typeof moduleItem === 'function') { const result = await promisify((moduleItem as UnknownFunction)(...args)); if (isRootNodeVisitor(result)) { return result; } } throw new CliError(`Invalid visitor. Expected a visitor or a function returning a visitor.`, [ `${pico.bold('Visitor')}: ${identifier}`, `${pico.bold('Path')}: ${path}`, ...(item ? [`${pico.bold('Item')}: ${item}`] : []), ]); } function isRootNodeVisitor(value: unknown): value is Visitor { return !!value && typeof value === 'object' && 'visitRoot' in value; } function getVisitorIdentifier(visitorConfig: ParsedVisitorConfig): string { const { index, script } = visitorConfig; let identifier = `visitor #${index}`; identifier += script ? ` in script "${script}"` : ''; return identifier; } ================================================ FILE: packages/cli/test/exports/commonjs.cjs ================================================ const path = require('path'); const { codama } = require('../../dist/index.node.cjs'); const configPath = path.join('test', 'exports', 'mock-config.json'); codama(['run', '-c', configPath]); ================================================ FILE: packages/cli/test/exports/mock-config.json ================================================ { "idl": "mock-idl.json", "before": ["@codama/visitors#identityVisitor"], "scripts": {} } ================================================ FILE: packages/cli/test/exports/mock-idl.json ================================================ { "kind": "rootNode", "standard": "codama", "version": "1.0.0", "program": { "kind": "programNode", "name": "myProgram", "accounts": [], "instructions": [], "definedTypes": [], "errors": [], "pdas": [] }, "additionalPrograms": [] } ================================================ FILE: packages/cli/test/exports/module.mjs ================================================ import path from 'path'; import { codama } from '../../dist/index.node.mjs'; const configPath = path.join('test', 'exports', 'mock-config.json'); codama(['run', '-c', configPath]); ================================================ FILE: packages/cli/test/index.test.ts ================================================ import { expect, test } from 'vitest'; import { createProgram } from '../src'; test('it exports a function to create a CLI program', () => { expect(typeof createProgram).toBe('function'); }); ================================================ FILE: packages/cli/tsconfig.declarations.json ================================================ { "compilerOptions": { "declaration": true, "declarationMap": true, "emitDeclarationOnly": true, "outDir": "./dist/types" }, "extends": "./tsconfig.json", "include": ["src/index.ts", "src/types"] } ================================================ FILE: packages/cli/tsconfig.json ================================================ { "$schema": "https://json.schemastore.org/tsconfig", "compilerOptions": { "module": "ESNext" }, "display": "codama", "extends": "../../tsconfig.json", "include": ["src", "test"] } ================================================ FILE: packages/cli/tsup.config.ts ================================================ import { defineConfig, Options as TsupConfig } from 'tsup'; import { getBuildConfig, getCliBuildConfig } from '../../tsup.config.base'; export default defineConfig([ removeAdditionalTreeShaking(getBuildConfig({ format: 'cjs', platform: 'node' })), removeAdditionalTreeShaking(getBuildConfig({ format: 'esm', platform: 'node' })), removeAdditionalTreeShaking(getCliBuildConfig()), ]); function removeAdditionalTreeShaking(config: TsupConfig): TsupConfig { return { ...config, // Treeshaking already happens with esbuild but tsup offers this options // for "better" treeshaking strategies using Rollup as an additional step. // The issue is Rollup now uses the deprecated "assert" import keyword by default // And tsup doesn't offer a way to change this behavior. Since the CLI package // relies on using the "with" keyword to dynamically import JSON files, // we can't use Rollup for treeshaking. treeshake: false, }; } ================================================ FILE: packages/cli/vitest.config.mts ================================================ import { defineConfig } from 'vitest/config'; import { getVitestConfig } from '../../vitest.config.base.mjs'; export default defineConfig({ test: { projects: [getVitestConfig('node')], }, }); ================================================ FILE: packages/dynamic-client/.gitignore ================================================ dist/ test/programs/anchor/.anchor/ test/programs/anchor/target/ test/programs/generated/ ================================================ FILE: packages/dynamic-client/.prettierignore ================================================ dist/ test/e2e/ test-ledger/ target/ CHANGELOG.md generated/ idls/ ================================================ FILE: packages/dynamic-client/LICENSE ================================================ MIT License Copyright (c) 2025 Codama Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: packages/dynamic-client/README.md ================================================ # Codama ➤ Dynamic Client [![npm][npm-image]][npm-url] [![npm-downloads][npm-downloads-image]][npm-url] [npm-downloads-image]: https://img.shields.io/npm/dm/@codama/dynamic-client.svg?style=flat [npm-image]: https://img.shields.io/npm/v/@codama/dynamic-client.svg?style=flat&label=%40codama%2Fdynamic-client [npm-url]: https://www.npmjs.com/package/@codama/dynamic-client This package provides a runtime Solana instruction builder that dynamically constructs `Instruction` (`@solana/instructions`) from Codama IDL and provides type generation for full TypeScript type safety. ## Installation ```sh pnpm install @codama/dynamic-client ``` > [!NOTE] > This package is **not** included in the main [`codama`](../library) package. ## Quick Start ### Untyped ```ts import { createProgramClient } from '@codama/dynamic-client'; import idl from './my-program-idl.json'; const client = createProgramClient(idl); const instruction = await client.methods .transferSol({ amount: 1_000_000_000 }) .accounts({ source: senderAddress, destination: receiverAddress }) .instruction(); ``` ### Typed with generated types ```ts import { createProgramClient } from '@codama/dynamic-client'; import type { MyProgramClient } from './generated/my-program-types'; import idl from './my-program-idl.json'; const client = createProgramClient(idl); // client.methods, .accounts(), args are now fully typed ``` ## API Reference ### `createProgramClient(idl, options?)` Creates a program client from a Codama IDL. | Parameter | Type | Description | | ------------------- | ------------------ | ----------------------------------------- | | `idl` | `object \| string` | Codama IDL object or JSON string | | `options.programId` | `AddressInput` | Override the program address from the IDL | Returns a `ProgramClient` (or `T` when a type parameter is provided). ### `ProgramClient` ```ts type InstructionName = CamelCaseString; type AccountName = CamelCaseString; type ProgramClient = { methods: Record ProgramMethodBuilder>; pdas?: Record Promise>; programAddress: Address; instructions: Map; root: RootNode; }; ``` ### `ProgramMethodBuilder` (fluent API) ```ts client.methods .myInstruction(args) // provide instruction arguments .accounts(accounts) // provide account addresses .signers(['accountName']) // optionally mark ambiguous accounts as signers .resolvers({ customResolver: async (argumentsInput, accountsInput) => {} }) // optionally provide custom resolver according to resolverValueNode in IDL .instruction(); // Promise ``` ### `AddressInput` Accepts any of: - `Address` (from `@solana/addresses`) - Legacy `PublicKey` (any object with `.toBase58()`) - Base58 string ## Accounts ### Automatic resolution rules Accounts (pda, program ids) with `defaultValue` are resolved automatically, hence can be omitted. | Account scenario | Type in `.accounts()` | Auto resolution | | --------------------------------------------------------------- | ------------------------------ | -------------------------------------------------------------------------------------------- | | Required account without `defaultValue` | `{ system: Address }` | No | | Required account with `defaultValue`
(PDA, programId, etc.) | `{ system?: Address }` | Auto-resolved to `defaultValue` if omitted | | Optional account (`isOptional: true`)
without `defaultValue` | `{ system: Address \| null }` | Resolved via `optionalAccountStrategy`,
if provided as `null` | | Optional account (`isOptional: true`)
with `defaultValue` | `{ system?: Address \| null }` | - `null` resolves via `optionalAccountStrategy`
- `undefined` resolves via `defaultValue` | ### Auto-resolved account addresses Accounts with `defaultValue` in the IDL are automatically resolved when omitted from `.accounts()`. This includes: - **PDA accounts** — derived from seeds defined in the IDL - **Program IDs** — resolved to known program addresses (e.g., System Program, Token Program) - **Constants** — resolved from constant value nodes You can always override auto-derived accounts by providing an explicit address. ### Optional accounts Pass `null` for optional accounts to be resolved according to `optionalAccountStrategy` (either will be `omitted` or replaced on `programId`): ```ts .accounts({ authority, program: programAddress, programData: null, // optional - resolved via optionalAccountStrategy }) ``` ### Ambiguous signers When an account has `isSigner: 'either'` in the IDL, use `.signers()` to explicitly mark it: ```ts .accounts({ owner: ownerAddress }) .signers(['owner']) ``` ### Custom resolvers When an account or argument is `resolverValueNode` in the IDL, provide a custom resolver function `.resolvers({ [resolverName]: async fn })` to help with account/arguments resolution: ```ts client.methods .create({ tokenStandard: 'NonFungible' }) .accounts({ owner: ownerAddress }) .resolvers({ resolveIsNonFungible: async (argumentsInput, accountsInput) => { return argumentsInput.tokenStandard === 'NonFungible'; }, }); ``` ## PDA Derivation ### Standalone ```ts const [address, bump] = await client.pdas.canonical({ program: programAddress, seed: 'idl', }); ``` ### Auto-derived in instructions Accounts with `pdaValueNode` defaults are resolved automatically. Seeds are pulled from other accounts and arguments in the instruction: ```ts // metadata PDA is auto-derived from program + seed const ix = await client.methods .initialize({ seed: 'idl', data: myData /* ... */ }) .accounts({ authority, program: programAddress, programData }) .instruction(); ``` Nested/dependent PDAs (where one PDA seed references another PDA) are resolved recursively. ## Arguments Arguments with `defaultValueStrategy: 'omitted'` (e.g., discriminators) are auto-encoded and should not be provided. ## Error Handling All errors are instances of `CodamaError` from `@codama/errors`: ```ts import { CodamaError, isCodamaError, CODAMA_ERROR__DYNAMIC_CLIENT__ACCOUNT_MISSING } from '@codama/dynamic-client'; try { const ix = await client.methods.transferSol({ amount: 100 }).accounts({}).instruction(); } catch (err) { if (isCodamaError(err, CODAMA_ERROR__DYNAMIC_CLIENT__ACCOUNT_MISSING)) { console.error(`Missing account: ${err.context.accountName}`); } } ``` ## CLI The package includes a CLI for generating TypeScript types from Codama IDL files. ```sh npx @codama/dynamic-client generate-client-types ``` Example: ```sh npx @codama/dynamic-client generate-client-types ./idl/codama.json ./generated ``` This reads the IDL file and writes a `*-types.ts` file to the output directory containing strongly-typed interfaces for all instructions, accounts, arguments, PDAs, and the program client. ### `generateClientTypes(idl)` The same is available as a TypeScript function: ```ts import { generateClientTypes } from '@codama/dynamic-client'; import type { RootNode } from 'codama'; import { readFileSync, writeFileSync } from 'node:fs'; const idl: RootNode = JSON.parse(readFileSync('./my-program-idl.json', 'utf-8')); const typesSource = generateClientTypes(idl); writeFileSync('./generated/my-program-idl-types.ts', typesSource); ``` ## Utilities ```ts import { toAddress, isPublicKeyLike } from '@codama/dynamic-client'; // Convert any AddressInput to Address const addr = toAddress('11111111111111111111111111111111'); const addr2 = toAddress(new PublicKey('...')); // Type guard for legacy PublicKey objects if (isPublicKeyLike(value)) { const addr = toAddress(value); } ``` ================================================ FILE: packages/dynamic-client/bin/cli.cjs ================================================ #!/usr/bin/env node const run = require('../dist/cli.cjs').run; run(process.argv); ================================================ FILE: packages/dynamic-client/package.json ================================================ { "name": "@codama/dynamic-client", "version": "0.1.0", "description": "Tool to dynamically build instructions based on Codama IDLs", "license": "MIT", "repository": { "type": "git", "url": "https://github.com/codama-idl/codama", "directory": "packages/dynamic-client" }, "bugs": { "url": "http://github.com/codama-idl/codama/issues" }, "bin": { "dynamic-client": "./bin/cli.cjs" }, "exports": { "types": "./dist/types/index.d.ts", "react-native": "./dist/index.react-native.mjs", "browser": { "import": "./dist/index.browser.mjs", "require": "./dist/index.browser.cjs" }, "node": { "import": "./dist/index.node.mjs", "require": "./dist/index.node.cjs" } }, "browser": { "./dist/index.node.cjs": "./dist/index.browser.cjs", "./dist/index.node.mjs": "./dist/index.browser.mjs" }, "main": "./dist/index.node.cjs", "module": "./dist/index.node.mjs", "react-native": "./dist/index.react-native.mjs", "types": "./dist/types/index.d.ts", "type": "commonjs", "files": [ "./dist/types", "./dist/index.*", "./dist/cli.*", "./bin/*" ], "sideEffects": false, "keywords": [ "solana", "framework", "standard", "specifications", "dynamic client" ], "scripts": { "build": "rimraf dist && tsup && tsc -p ./tsconfig.declarations.json", "dev": "vitest --project node", "lint": "pnpm generate-program-types && eslint . && prettier --check .", "lint:fix": "pnpm generate-program-types && eslint --fix . && prettier --write .", "test": "pnpm test:setup && pnpm test:types && pnpm test:treeshakability && pnpm test:unit", "test:setup": "pnpm test:anchor:build && ( [ -n \"$CI\" ] || pnpm generate-idl-from-anchor ) && pnpm generate-program-types", "test:anchor:build": "cd test/programs/anchor && anchor build", "test:treeshakability": "for file in dist/index.*.mjs; do agadoo $file; done", "test:types": "tsc --noEmit", "test:unit": "vitest run", "generate-idl-from-anchor": "node ./scripts/generate-idl-from-anchor.mjs", "generate-program-types": "for f in test/programs/idls/*.json; do node ./bin/cli.cjs generate-client-types \"$f\" ./test/programs/generated; done" }, "dependencies": { "@codama/dynamic-codecs": "workspace:*", "@codama/errors": "workspace:*", "@solana/addresses": "^5.3.0", "@solana/codecs": "^5.3.0", "@solana/instructions": "^5.3.0", "codama": "workspace:*", "commander": "^14.0.2", "superstruct": "^2.0.2" }, "devDependencies": { "@codama/nodes-from-anchor": "workspace:*", "@codama/renderers-core": "workspace:*", "@metaplex-foundation/mpl-token-metadata-kit": "^0.0.2", "@solana-program/program-metadata": "^0.5.1", "@solana-program/token": "0.10.0", "@solana-program/token-2022": "^0.9.0", "@solana/kit": "6.5.0", "litesvm": "1.0.0", "sas-lib": "^1.0.10" }, "browserslist": [ "supports bigint and not dead", "maintained node versions" ] } ================================================ FILE: packages/dynamic-client/scripts/generate-idl-from-anchor.mjs ================================================ import { readFileSync } from 'node:fs'; import path from 'node:path'; import { rootNodeFromAnchor } from '@codama/nodes-from-anchor'; import { writeFile } from '@codama/renderers-core'; import { createFromRoot } from 'codama'; // This script generates Codama IDL from Anchor programs for tests. const packageRoot = process.cwd(); const programs = ['example', 'blog']; for (const program of programs) { const idlPath = path.join(packageRoot, 'test', 'programs', 'anchor', 'target', 'idl', `${program}.json`); console.log(`Start generation from IDL: ${idlPath}`); const idl = JSON.parse(readFileSync(idlPath, 'utf-8')); console.log('Creating codama client..'); const codama = createFromRoot(rootNodeFromAnchor(idl)); const pathToIdl = path.join(packageRoot, 'test', 'programs', 'idls', `${program}-idl.json`); console.log(`Writing Codama IDL to: ${pathToIdl}`); const codamaJson = JSON.parse(codama.getJson()); const json = JSON.stringify(codamaJson, null, 4) + '\n'; writeFile(pathToIdl, json); console.log(`Done: ${program}`); } ================================================ FILE: packages/dynamic-client/src/cli/commands/generate-client-types/generate-client-types-from-file.ts ================================================ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'; import path from 'node:path'; import { createFromJson, type RootNode } from 'codama'; import { generateClientTypes } from './generate-client-types'; export function generateClientTypesFromFile(codamaIdlPath: string, outputDirPath: string) { const idlPath = path.resolve(codamaIdlPath); const outputDir = path.resolve(outputDirPath); if (!existsSync(idlPath)) { console.error(`Error: IDL file not found: ${idlPath}`); process.exit(1); } console.log(`Reading IDL from: ${idlPath}`); let idlJson: string; try { idlJson = readFileSync(idlPath, 'utf-8'); } catch (err) { console.error(`Error reading IDL file: ${err instanceof Error ? err.message : String(err)}`); process.exit(1); } let idl: RootNode; try { idl = createFromJson(idlJson).getRoot(); } catch (err) { console.error( `Error: ${idlPath} is not valid Codama JSON: ${err instanceof Error ? err.message : String(err)}`, ); process.exit(1); } let types: string = ''; try { console.log(`Generating types for program: ${idl.program.name}`); types = generateClientTypes(idl); } catch (err) { console.error(`Error generating client types: ${err instanceof Error ? err.message : String(err)}`); process.exit(1); } try { mkdirSync(outputDir, { recursive: true }); const fileName = path.basename(idlPath); const outputFile = fileName.replace(/\.json$/, '-types.ts'); const outputPath = path.join(outputDir, outputFile); console.log(`Writing types to: ${outputPath}`); writeFileSync(outputPath, types, 'utf-8'); console.log('Done!'); } catch (err) { console.error(`Error writing generated types: ${err instanceof Error ? err.message : String(err)}`); process.exit(1); } } ================================================ FILE: packages/dynamic-client/src/cli/commands/generate-client-types/generate-client-types.ts ================================================ import type { DefinedTypeNode, InstructionAccountNode, InstructionInputValueNode, InstructionNode, PdaNode, RootNode, TypeNode, } from 'codama'; import { OPTIONAL_NODE_KINDS } from '../../../shared/nodes'; /** * Generate TypeScript type for program client. */ export function generateClientTypes(idl: RootNode): string { const programName = toPascalCase(idl.program.name); const definedTypes = idl.program.definedTypes ?? []; const pdaMap = collectPdaNodesFromIdl(idl); const hasPdas = pdaMap.size > 0; const addressImports = hasPdas ? 'Address, ProgramDerivedAddress' : 'Address'; let output = `/** * Auto-generated types for strongly-typed ProgramClient * DO NOT EDIT - Generated by @codama/dynamic-client generate-client-types * * Note: When the IDL contains types that cannot be resolved (e.g. unsupported * kind, missing definition), argument types fall back to \`unknown\` instead of * \`any\`. Consumers should narrow these values before use. */ import type { InstructionNode, RootNode } from 'codama'; import type { ${addressImports} } from '@solana/addresses'; import type { Instruction } from '@solana/instructions'; export type ResolverFn< TArgumentsInput = Record, TAccountsInput = Record > = (argumentsInput: TArgumentsInput, accountsInput: TAccountsInput) => Promise; /** * Method builder interface. */ export type MethodBuilder> = { accounts(accounts: TAccounts): MethodBuilder; resolvers(resolvers: Partial): MethodBuilder; signers(signers: TSigners): MethodBuilder; instruction(): Promise; }; `; for (const ix of idl.program.instructions) { const typeName = toPascalCase(ix.name); // Build args interface const args = ix.arguments.filter(arg => arg.defaultValueStrategy !== 'omitted'); const remainingAccountArgs = (ix.remainingAccounts ?? []).filter(ra => ra.value.kind === 'argumentValueNode'); let argsRef = 'void'; if (args.length > 0 || remainingAccountArgs.length > 0) { const argsInterfaceName = `${typeName}Args`; output += `export type ${argsInterfaceName} = {\n`; for (const arg of args) { const tsType = codamaTypeToTS(arg.type, definedTypes); const isOptional = OPTIONAL_NODE_KINDS.includes(arg.type.kind); const sep = isOptional ? '?:' : ':'; output += ` ${arg.name}${sep} ${tsType};\n`; } for (const ra of remainingAccountArgs) { const sep = ra.isOptional ? '?:' : ':'; output += ` ${ra.value.name}${sep} Address[];\n`; } output += '};\n\n'; argsRef = argsInterfaceName; } // Build accounts interface // these ValueNodes don't have default value and must be provided if required. const nonResolvableValueNodes = ['payerValueNode', 'identityValueNode']; function isAccAutoResolvable(acc: InstructionAccountNode): boolean { if (acc.defaultValue == null) return false; return !nonResolvableValueNodes.includes(acc.defaultValue.kind); } const accountsInterfaceName = `${typeName}Accounts`; if (ix.accounts.length > 0) { output += `export type ${accountsInterfaceName} = {\n`; for (const acc of ix.accounts) { // Omittable accounts have a defaultValue that can be auto-resolved, so they can be omitted from .accounts(). // When null: resolved via optionalAccountStrategy. // When undefined: resolved via defaultValue. const omittable = isAccAutoResolvable(acc) ? '?' : ''; const type = acc.isOptional ? 'Address | null' : 'Address'; output += ` ${acc.name}${omittable}: ${type};\n`; } output += '} & Record;\n\n'; } else { output += `export type ${accountsInterfaceName} = Record;\n\n`; } // Collect all ambiguous isSigner: "either" account names const eitherSignerAccounts = ix.accounts.filter(acc => acc.isSigner === 'either').map(acc => `'${acc.name}'`); if (eitherSignerAccounts.length > 0) { output += `export type ${typeName}Signers = (${eitherSignerAccounts.join(' | ')})[];\n\n`; } // Collect resolver names for this instruction const resolverNames = collectResolverNames(ix); let resolversRef = ''; if (resolverNames.size > 0) { const resolversTypeName = `${typeName}Resolvers`; output += `export type ${resolversTypeName} = {\n`; for (const name of resolverNames) { output += ` ${name}: ResolverFn<${argsRef === 'void' ? 'Record' : argsRef}, ${accountsInterfaceName}>;\n`; } output += '};\n\n'; resolversRef = resolversTypeName; } // Generate method type const hasRequiredArgs = args.some(arg => !OPTIONAL_NODE_KINDS.includes(arg.type.kind)); const hasRequiredRemainingAccounts = remainingAccountArgs.some(ra => !ra.isOptional); const allArgsOptional = !hasRequiredArgs && !hasRequiredRemainingAccounts; const argsParam = argsRef === 'void' ? '' : allArgsOptional ? `args?: ${argsRef}` : `args: ${argsRef}`; const signersGeneric = eitherSignerAccounts.length > 0 ? `${typeName}Signers` : 'string[]'; const resolversGeneric = resolversRef ? `, ${resolversRef}` : ''; const methodSignature = `(${argsParam}) => MethodBuilder<${accountsInterfaceName}, ${signersGeneric}${resolversGeneric}>`; output += `export type ${typeName}Method = ${methodSignature};\n\n`; } output += `/** * Strongly-typed methods for ${programName}. */ export type ${programName}Methods = {\n`; for (const ix of idl.program.instructions) { const typeName = toPascalCase(ix.name); output += ` ${ix.name}: ${typeName}Method;\n`; } output += '};\n\n'; // Generate PDA seed types and pdas namespace if (pdaMap.size > 0) { for (const [pdaName, pdaNode] of pdaMap) { const typeName = toPascalCase(pdaName); const variableSeeds = (pdaNode.seeds ?? []).filter(s => s.kind === 'variablePdaSeedNode'); if (variableSeeds.length > 0) { output += `export type ${typeName}PdaSeeds = {\n`; for (const seed of variableSeeds) { const tsType = seed.type ? codamaTypeToTS(seed.type, definedTypes) : 'unknown'; output += ` ${seed.name}: ${tsType};\n`; } output += '};\n\n'; } } output += `/**\n * Strongly-typed PDAs for ${programName}.\n */\n`; output += `export type ${programName}Pdas = {\n`; for (const [pdaName, pdaNode] of pdaMap) { const typeName = toPascalCase(pdaName); const variableSeeds = (pdaNode.seeds ?? []).filter(s => s.kind === 'variablePdaSeedNode'); const seedsParam = variableSeeds.length > 0 ? `seeds: ${typeName}PdaSeeds` : `seeds?: Record`; output += ` ${pdaName}: (${seedsParam}) => Promise;\n`; } output += '};\n\n'; } const pdasProp = pdaMap.size > 0 ? ` pdas: ${programName}Pdas;\n` : ''; output += `/** * Strongly-typed program client for ${programName}. */ export type ${programName}ProgramClient = { methods: ${programName}Methods; ${pdasProp} programAddress: Address; root: RootNode; instructions: Map; }; `; return output; } /** * Convert Codama type to TypeScript type string. */ function codamaTypeToTS(type: TypeNode | undefined, definedTypes: DefinedTypeNode[]): string { if (!type || typeof type !== 'object') return 'unknown'; switch (type.kind) { case 'numberTypeNode': return ['u64', 'u128', 'i64', 'i128'].includes(type.format ?? '') ? 'number | bigint' : 'number'; case 'publicKeyTypeNode': return 'Address'; case 'stringTypeNode': return 'string'; case 'booleanTypeNode': return 'boolean'; case 'optionTypeNode': return `${codamaTypeToTS(type.item, definedTypes)} | null`; case 'remainderOptionTypeNode': case 'zeroableOptionTypeNode': return `${codamaTypeToTS(type.item, definedTypes)} | null`; case 'bytesTypeNode': return 'Uint8Array'; case 'fixedSizeTypeNode': case 'sizePrefixTypeNode': case 'hiddenPrefixTypeNode': case 'preOffsetTypeNode': case 'postOffsetTypeNode': case 'hiddenSuffixTypeNode': case 'sentinelTypeNode': return codamaTypeToTS(type.type, definedTypes); case 'amountTypeNode': case 'solAmountTypeNode': return 'number | bigint'; case 'structTypeNode': { if (!type.fields || type.fields.length === 0) return '{}'; const fields = type.fields .filter(f => f.defaultValueStrategy !== 'omitted') .map(f => `${f.name}: ${codamaTypeToTS(f.type, definedTypes)}`); if (fields.length === 0) return '{}'; return `{ ${fields.join('; ')} }`; } case 'enumTypeNode': { if (!type.variants || type.variants.length === 0) return 'unknown'; const allEmpty = type.variants.every(v => v.kind === 'enumEmptyVariantTypeNode'); if (allEmpty) { return type.variants.map(v => `'${v.name}'`).join(' | '); } // Enum with struct/tuple variants — discriminated union const variantTypes = type.variants.map(v => { if (v.kind === 'enumEmptyVariantTypeNode') { return `{ __kind: '${v.name}' }`; } if (v.kind === 'enumStructVariantTypeNode' && v.struct) { const inner = codamaTypeToTS(v.struct, definedTypes); return `{ __kind: '${v.name}' } & ${inner}`; } if (v.kind === 'enumTupleVariantTypeNode' && v.tuple) { const inner = codamaTypeToTS(v.tuple, definedTypes); return `{ __kind: '${v.name}'; fields: ${inner} }`; } return `{ __kind: '${v.name}' }`; }); return variantTypes.join(' | '); } case 'tupleTypeNode': { if (!type.items || type.items.length === 0) return '[]'; const items = type.items.map(i => codamaTypeToTS(i, definedTypes)); return `[${items.join(', ')}]`; } case 'arrayTypeNode': case 'setTypeNode': { const itemType = codamaTypeToTS(type.item, definedTypes); const needsParens = itemType.includes(' | ') || itemType.includes(' & '); return needsParens ? `(${itemType})[]` : `${itemType}[]`; } case 'mapTypeNode': { const v = codamaTypeToTS(type.value, definedTypes); return `Record`; } case 'definedTypeLinkNode': { if (!type.name) return 'unknown'; const def = definedTypes.find(d => d.name === type.name); if (!def) return 'unknown'; return codamaTypeToTS(def.type, definedTypes); } case 'dateTimeTypeNode': { return codamaTypeToTS(type.number, definedTypes); } default: type['kind'] satisfies never; return 'unknown'; } } function collectPdaNodesFromIdl(idl: RootNode): Map { const pdas = new Map(); for (const pda of idl.program.pdas ?? []) { pdas.set(pda.name, pda); } for (const ix of idl.program.instructions) { for (const acc of ix.accounts) { if (!acc.defaultValue || acc.defaultValue.kind !== 'pdaValueNode') continue; const pdaDef = acc.defaultValue.pda; if (!pdaDef || pdaDef.kind !== 'pdaNode') continue; if (!pdas.has(pdaDef.name)) { pdas.set(pdaDef.name, pdaDef); } } } return pdas; } /** * Collects all unique resolverValueNode names from an instruction's accounts and arguments. */ function collectResolverNames(ix: InstructionNode): Set { const names = new Set(); function extractResolverNodeName(node: InstructionInputValueNode | undefined): void { if (!node) return; if (node.kind === 'resolverValueNode' && node.name) { names.add(node.name); } else if (node.kind === 'conditionalValueNode') { extractResolverNodeName(node.condition); extractResolverNodeName(node.ifTrue); extractResolverNodeName(node.ifFalse); } } for (const acc of ix.accounts) { extractResolverNodeName(acc.defaultValue); } for (const arg of ix.arguments) { extractResolverNodeName(arg.defaultValue); } return names; } function toPascalCase(str: string): string { return str .split(/[-_]/) .map(word => word.charAt(0).toUpperCase() + word.slice(1)) .join(''); } ================================================ FILE: packages/dynamic-client/src/cli/commands/generate-client-types/register-command.ts ================================================ import type { Command } from 'commander'; import { generateClientTypesFromFile } from './generate-client-types-from-file'; export function registerGenerateClientTypesCommand(program: Command): void { program .command('generate-client-types') .description('Generate TypeScript types from a Codama IDL JSON file') .argument('', 'Path to a Codama IDL JSON file (e.g., ./idl/codama.json)') .argument('', 'Path to the output directory for the generated .ts file, e.g., ./generated') .action((idlArg: string, outputDirArg: string) => { generateClientTypesFromFile(idlArg, outputDirArg); }); } ================================================ FILE: packages/dynamic-client/src/cli/commands/index.ts ================================================ import type { Command } from 'commander'; import { registerGenerateClientTypesCommand } from './generate-client-types/register-command'; export function registerCommands(program: Command): void { registerGenerateClientTypesCommand(program); } ================================================ FILE: packages/dynamic-client/src/cli/index.ts ================================================ import { createProgram } from './program'; const program = createProgram(); export function run(argv: string[]): void { // Show help when invoked with no arguments. if (argv.length <= 2) { program.outputHelp(); return; } program.parse(argv); } ================================================ FILE: packages/dynamic-client/src/cli/program.ts ================================================ import { Command } from 'commander'; import { registerCommands } from './commands'; export function createProgram(): Command { const program = new Command(); program.name('dynamic-client').description('CLI for @codama/dynamic-client').showHelpAfterError(true); registerCommands(program); return program; } ================================================ FILE: packages/dynamic-client/src/index.ts ================================================ export type { ProgramDerivedAddress } from '@solana/addresses'; export { isPublicKeyLike, toAddress } from './shared/address'; export type { AddressInput, PublicKeyLike } from './shared/address'; export { CodamaError, isCodamaError } from '@codama/errors'; export { CODAMA_ERROR__DYNAMIC_CLIENT__ACCOUNT_MISSING, CODAMA_ERROR__DYNAMIC_CLIENT__ACCOUNT_RESOLVER_MISSING, CODAMA_ERROR__DYNAMIC_CLIENT__ARGUMENT_MISSING, CODAMA_ERROR__DYNAMIC_CLIENT__CANNOT_CONVERT_TO_ADDRESS, CODAMA_ERROR__DYNAMIC_CLIENT__CIRCULAR_ACCOUNT_DEPENDENCY, CODAMA_ERROR__DYNAMIC_CLIENT__DEFAULT_VALUE_MISSING, CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_DERIVE_PDA, CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_ENCODE_ARGUMENT, CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_EXECUTE_RESOLVER, CODAMA_ERROR__DYNAMIC_CLIENT__INSTRUCTION_NOT_FOUND, CODAMA_ERROR__DYNAMIC_CLIENT__INVALID_ACCOUNT_ADDRESS, CODAMA_ERROR__DYNAMIC_CLIENT__INVALID_ARGUMENT_INPUT, CODAMA_ERROR__DYNAMIC_CLIENT__INVARIANT_VIOLATION, CODAMA_ERROR__DYNAMIC_CLIENT__NODE_REFERENCE_NOT_FOUND, CODAMA_ERROR__DYNAMIC_CLIENT__PDA_NOT_FOUND, CODAMA_ERROR__DYNAMIC_CLIENT__UNEXPECTED_ADDRESS_TYPE, CODAMA_ERROR__DYNAMIC_CLIENT__UNEXPECTED_ARGUMENT_TYPE, CODAMA_ERROR__DYNAMIC_CLIENT__UNSUPPORTED_NODE, CODAMA_ERROR__DYNAMIC_CLIENT__UNSUPPORTED_OPTIONAL_ACCOUNT_STRATEGY, CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_VALIDATE_INPUT, } from '@codama/errors'; export type { AccountsInput, ArgumentsInput } from './shared/types'; export { createProgramClient } from './program-client/create-program-client'; export type { CreateProgramClientOptions, IdlInput, ProgramClient, ProgramMethodBuilder, } from './program-client/create-program-client'; export { generateClientTypes } from './cli/commands/generate-client-types/generate-client-types'; ================================================ FILE: packages/dynamic-client/src/instruction-encoding/accounts/create-account-meta.ts ================================================ import { CODAMA_ERROR__DYNAMIC_CLIENT__ACCOUNT_MISSING, CODAMA_ERROR__DYNAMIC_CLIENT__ARGUMENT_MISSING, CODAMA_ERROR__DYNAMIC_CLIENT__INVALID_ARGUMENT_INPUT, CODAMA_ERROR__DYNAMIC_CLIENT__UNEXPECTED_ADDRESS_TYPE, CODAMA_ERROR__UNEXPECTED_NODE_KIND, CodamaError, } from '@codama/errors'; import type { Address } from '@solana/addresses'; import type { AccountMeta } from '@solana/instructions'; import { AccountRole } from '@solana/instructions'; import { type InstructionAccountNode, type InstructionNode, isNode, type RootNode } from 'codama'; import { isConvertibleAddress, toAddress } from '../../shared/address'; import type { AccountsInput, ArgumentsInput, EitherSigners, ResolversInput } from '../../shared/types'; import { formatValueType, safeStringify } from '../../shared/util'; import { resolveAccountAddress } from '../resolvers/resolve-account-address'; type ResolvedAccount = { address: Address | null; optional: boolean; role: AccountRole; }; type ResolvedAccountWithAddress = ResolvedAccount & { address: Address }; /** * Resolves account addresses and creates AccountMeta for each account in the instruction by evaluating their default values. * Handles optional accounts based on the instruction's optionalAccountStrategy. * Throws errors if required accounts are missing or cannot be resolved. */ export async function createAccountMeta( root: RootNode, ixNode: InstructionNode, argumentsInput: ArgumentsInput = {}, accountsInput: AccountsInput = {}, signers: EitherSigners = [], resolversInput: ResolversInput = {}, ): Promise { const programAddress = toAddress(root.program.publicKey); const resolvedAccounts = await Promise.all( ixNode.accounts.map>(async ixAccountNode => { const accountAddressInput = accountsInput?.[ixAccountNode.name]; const isAccountProvided = accountAddressInput !== undefined && accountAddressInput !== null; // Accounts with default values can be omitted, as they can be resolved from default value if (!isAccountProvided && !ixAccountNode.isOptional && !ixAccountNode.defaultValue) { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__ACCOUNT_MISSING, { accountName: ixAccountNode.name, instructionName: ixNode.name, }); } let resolvedAccountAddress: Address | null = null; if (!isAccountProvided) { resolvedAccountAddress = await resolveAccountAddress({ accountAddressInput, accountsInput, argumentsInput, ixAccountNode, ixNode, resolutionPath: [], resolversInput, root, }); } const finalAddress = isAccountProvided ? toAddress(accountAddressInput) : resolvedAccountAddress; // Optional accounts resolved via "programId" optionalAccountStrategy get the program address, // which cannot be writable on-chain — downgrade to readonly. // E.g. PMP's setData instruction `buffer` account. (isWritable, isOptional and "programId" strategy). // But when buffer is null it resolves to the program address which cannot be writable, hence must be downgraded to readonly. const role = ixAccountNode.isOptional && !isAccountProvided && ixNode.optionalAccountStrategy === 'programId' && finalAddress === programAddress ? getReadonlyAccountRole(ixAccountNode, signers) : getAccountRole(ixAccountNode, signers); return { address: finalAddress, optional: Boolean(ixAccountNode.isOptional), role, }; }), ); const accountMetas: AccountMeta[] = resolvedAccounts // Filter out optional accounts with "omitted" strategy (nulls). .filter((acc): acc is ResolvedAccountWithAddress => acc.address !== null) .map(acc => ({ address: acc.address, role: acc.role, })); // Resolve remaining accounts from argument values // https://github.com/codama-idl/codama/blob/main/packages/nodes/docs/InstructionRemainingAccountsNode.md for (const remainingNode of ixNode.remainingAccounts ?? []) { if (!isNode(remainingNode.value, 'argumentValueNode')) { throw new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, { expectedKinds: ['argumentValueNode'], kind: remainingNode.value.kind, node: remainingNode.value, }); } const addresses = argumentsInput[remainingNode.value.name]; if (addresses === undefined) { // Required remaining accounts must be provided. if (!remainingNode.isOptional) { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__ARGUMENT_MISSING, { argumentName: remainingNode.value.name, instructionName: ixNode.name, }); } // Optional remaining accounts can be safely omitted. continue; } if (!Array.isArray(addresses)) { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__INVALID_ARGUMENT_INPUT, { argumentName: remainingNode.value.name, expectedType: 'Address[]', value: safeStringify(addresses), }); } const role = getRemainingAccountRole(remainingNode.isSigner, remainingNode.isWritable); for (let i = 0; i < addresses.length; i++) { const addr: unknown = addresses[i]; if (!isConvertibleAddress(addr)) { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__UNEXPECTED_ADDRESS_TYPE, { accountName: `${remainingNode.value.name}[${i}]`, actualType: formatValueType(addr), expectedType: 'Address | PublicKey', }); } accountMetas.push({ address: toAddress(addr), role }); } } return accountMetas; } // TODO: 'either' is treated as signer — this works for Token Program multisig signers, // but may need refinement for programs where 'either' accounts are sometimes non-signers. function getRemainingAccountRole(isSigner?: boolean | 'either', isWritable?: boolean): AccountRole { const signer = isSigner === true || isSigner === 'either'; const writable = isWritable === true; if (writable && signer) return AccountRole.WRITABLE_SIGNER; if (writable) return AccountRole.WRITABLE; if (signer) return AccountRole.READONLY_SIGNER; return AccountRole.READONLY; } function getAccountRole(acc: InstructionAccountNode, signers: string[] | undefined): AccountRole { const isSigner = isSignerAccount(acc, signers ?? []); if (acc.isWritable && isSigner) { return AccountRole.WRITABLE_SIGNER; } if (acc.isWritable) { return AccountRole.WRITABLE; } if (isSigner) { return AccountRole.READONLY_SIGNER; } return AccountRole.READONLY; } function getReadonlyAccountRole(acc: InstructionAccountNode, signers: string[] | undefined): AccountRole { const isSigner = isSignerAccount(acc, signers ?? []); return isSigner ? AccountRole.READONLY_SIGNER : AccountRole.READONLY; } function isSignerAccount(acc: InstructionAccountNode, signers: string[]) { if (acc.isSigner === 'either') { return signers.includes(acc.name); } return acc.isSigner === true; } ================================================ FILE: packages/dynamic-client/src/instruction-encoding/accounts/index.ts ================================================ export { createAccountMeta } from './create-account-meta'; export { createAccountsInputValidator } from './validate-accounts-input'; ================================================ FILE: packages/dynamic-client/src/instruction-encoding/accounts/validate-accounts-input.ts ================================================ import { CODAMA_ERROR__DYNAMIC_CLIENT__ACCOUNT_MISSING, CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_VALIDATE_INPUT, CODAMA_ERROR__DYNAMIC_CLIENT__INVALID_ACCOUNT_ADDRESS, CodamaError, } from '@codama/errors'; import { camelCase, type InstructionNode } from 'codama'; import { assert, StructError } from 'superstruct'; import type { AccountsInput } from '../../shared/types'; import { safeStringify } from '../../shared/util'; import { createIxAccountsValidator } from '../validators'; /** * Creates a validation function for InstructionAccountNodes. * Pre-built superstruct validator ensures all required accounts are provided and have valid addresses. * Skips validation for instructions without accounts. */ export function createAccountsInputValidator(ixNode: InstructionNode) { const validator = ixNode.accounts.length ? createIxAccountsValidator(ixNode.accounts) : null; return (accountsInput: AccountsInput = {}) => { if (!validator) return; try { assert(accountsInput, validator); } catch (error) { if (error instanceof StructError) { const key = error.key as string; const value = error.value as unknown; if (value == null) { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__ACCOUNT_MISSING, { accountName: camelCase(key), instructionName: ixNode.name, }); } else { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__INVALID_ACCOUNT_ADDRESS, { accountName: camelCase(key), value: safeStringify(value), }); } } throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_VALIDATE_INPUT, { cause: error, message: 'Unexpected validation error', }); } }; } ================================================ FILE: packages/dynamic-client/src/instruction-encoding/arguments/encode-instruction-arguments.ts ================================================ import { getNodeCodec, type ReadonlyUint8Array } from '@codama/dynamic-codecs'; import { CODAMA_ERROR__DYNAMIC_CLIENT__ARGUMENT_MISSING, CODAMA_ERROR__DYNAMIC_CLIENT__DEFAULT_VALUE_MISSING, CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_ENCODE_ARGUMENT, CODAMA_ERROR__UNEXPECTED_NODE_KIND, CodamaError, } from '@codama/errors'; import { type Codec, mergeBytes } from '@solana/codecs'; import type { InstructionNode, RootNode } from 'codama'; import { visitOrElse } from 'codama'; import type { ArgumentsInput } from '../../shared/types'; import { createDefaultValueEncoderVisitor, createInputValueTransformer, DEFAULT_VALUE_ENCODER_SUPPORTED_NODE_KINDS, } from '../visitors'; import { isOmittedArgument, isOptionalArgument } from './shared'; /** * Encodes all instruction arguments into a single byte array. * Iterates over each InstructionArgumentNode and encodes based on its category: * * Omitted arguments use their default value. * Optional arguments are encoded as null. * Required arguments are transformed from user input and then encoded. */ export function encodeInstructionArguments( root: RootNode, ix: InstructionNode, argumentsInput: ArgumentsInput = {}, ): ReadonlyUint8Array { const chunks = ix.arguments.map(ixArgumentNode => { const input = argumentsInput?.[ixArgumentNode.name]; const nodeCodec = getNodeCodec([root, root.program, ix, ixArgumentNode]); if (isOmittedArgument(ixArgumentNode)) { return encodeOmittedArgument(ix, ixArgumentNode, nodeCodec); } else if (isOptionalArgument(ixArgumentNode, input)) { return encodeOptionalArgument(ix, ixArgumentNode, nodeCodec); } else { return encodeRequiredArgument(root, ix, ixArgumentNode, input, nodeCodec); } }); return mergeBytes(chunks as Uint8Array[]); } function encodeOmittedArgument( ix: InstructionNode, ixArgumentNode: InstructionNode['arguments'][number], nodeCodec: Codec, ): ReadonlyUint8Array { const defaultValue = ixArgumentNode.defaultValue; if (defaultValue === undefined) { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__DEFAULT_VALUE_MISSING, { argumentName: ixArgumentNode.name, instructionName: ix.name, }); } const visitor = createDefaultValueEncoderVisitor(nodeCodec); return visitOrElse(defaultValue, visitor, node => { throw new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, { expectedKinds: [...DEFAULT_VALUE_ENCODER_SUPPORTED_NODE_KINDS], kind: node.kind, node, }); }); } function encodeOptionalArgument( ix: InstructionNode, ixArgumentNode: InstructionNode['arguments'][number], nodeCodec: Codec, ): ReadonlyUint8Array { try { return nodeCodec.encode(null); } catch (error) { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_ENCODE_ARGUMENT, { argumentName: ixArgumentNode.name, cause: error, instructionName: ix.name, }); } } function encodeRequiredArgument( root: RootNode, ix: InstructionNode, ixArgumentNode: InstructionNode['arguments'][number], input: ArgumentsInput[string], nodeCodec: Codec, ): ReadonlyUint8Array { if (input === undefined) { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__ARGUMENT_MISSING, { argumentName: ixArgumentNode.name, instructionName: ix.name, }); } const transformer = createInputValueTransformer(ixArgumentNode.type, root, { bytesEncoding: 'base16', }); const transformedInput = transformer(input); try { return nodeCodec.encode(transformedInput); } catch (error) { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_ENCODE_ARGUMENT, { argumentName: ixArgumentNode.name, cause: error, instructionName: ix.name, }); } } ================================================ FILE: packages/dynamic-client/src/instruction-encoding/arguments/index.ts ================================================ export { encodeInstructionArguments } from './encode-instruction-arguments'; export { createArgumentsInputValidator } from './validate-arguments-input'; export { resolveArgumentDefaultsFromCustomResolvers } from './resolve-argument-from-custom-resolvers'; ================================================ FILE: packages/dynamic-client/src/instruction-encoding/arguments/resolve-argument-from-custom-resolvers.ts ================================================ import { CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_EXECUTE_RESOLVER, CodamaError } from '@codama/errors'; import type { InstructionNode } from 'codama'; import { isNode } from 'codama'; import type { AccountsInput, ArgumentsInput, ResolversInput } from '../../shared/types'; import { isOmittedArgument } from './shared'; /** * Resolves argument defaults from user-provided resolvers. * For each argument that has a ResolverValueNode and is not provided by argumentsInput, * try to invoke the corresponding resolver function and fill ArgumentsInput with the resolved values. */ export async function resolveArgumentDefaultsFromCustomResolvers( ixNode: InstructionNode, argumentsInput: ArgumentsInput = {}, accountsInput: AccountsInput = {}, resolversInput: ResolversInput = {}, ): Promise { const resolvedArgumentsInput = { ...argumentsInput }; const allArguments = [...ixNode.arguments, ...(ixNode.extraArguments ?? [])]; for (const argumentNode of allArguments) { if (resolvedArgumentsInput[argumentNode.name] !== undefined) continue; if (isOmittedArgument(argumentNode)) continue; if (!isNode(argumentNode.defaultValue, 'resolverValueNode')) continue; const resolverFn = resolversInput[argumentNode.defaultValue.name]; // If no resolver provided — skip and let the encoding step handle it: // Optional arguments will be encoded as none // Required arguments will emit error if (!resolverFn) continue; try { resolvedArgumentsInput[argumentNode.name] = await resolverFn(resolvedArgumentsInput, accountsInput); } catch (error) { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_EXECUTE_RESOLVER, { cause: error, resolverName: argumentNode.defaultValue.name, targetKind: 'instructionArgumentNode', targetName: argumentNode.name, }); } } return resolvedArgumentsInput; } ================================================ FILE: packages/dynamic-client/src/instruction-encoding/arguments/shared.ts ================================================ import type { InstructionArgumentNode } from 'codama'; import { OPTIONAL_NODE_KINDS } from '../../shared/nodes'; export function isOmittedArgument(node: InstructionArgumentNode) { return node.defaultValueStrategy === 'omitted'; } export function isOptionalArgument(ixArgumentNode: InstructionArgumentNode, input: unknown) { return OPTIONAL_NODE_KINDS.includes(ixArgumentNode.type.kind) && (input === null || input === undefined); } ================================================ FILE: packages/dynamic-client/src/instruction-encoding/arguments/validate-arguments-input.ts ================================================ import { CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_VALIDATE_INPUT, CodamaError } from '@codama/errors'; import type { InstructionNode, RootNode } from 'codama'; import type { Failure } from 'superstruct'; import { assert, StructError } from 'superstruct'; import type { ArgumentsInput } from '../../shared/types'; import { safeStringify } from '../../shared/util'; import { createIxArgumentsValidator } from '../validators'; import { isOmittedArgument } from './shared'; /** * Creates a cached validation function for InstructionArgumentNodes. * * Skips "omitted" arguments. * Arguments with resolverValueNode defaults are expected to use optionTypeNode and NOT filtered out here. * Optional validation allows undefined so custom resolvers will fill default values after validation. */ export function createArgumentsInputValidator(root: RootNode, ixNode: InstructionNode) { const requiredArguments = ixNode.arguments.filter(arg => arg?.defaultValueStrategy !== 'omitted'); const validator = requiredArguments.length ? createIxArgumentsValidator(ixNode.name, requiredArguments, root.program.definedTypes) : null; return (argumentsInput: ArgumentsInput = {}) => { // Ensure arguments with "omitted" defaultValueStrategy are not provided in argumentsInput. validateOmittedArguments(ixNode, argumentsInput); if (!validator) return; const filteredInput = filterRemainingAccountArguments(ixNode, argumentsInput); try { assert(filteredInput, validator); } catch (error) { if (!(error instanceof StructError)) { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_VALIDATE_INPUT, { cause: error, message: 'Unexpected validation error', }); } const formattedMessage = error.failures().map(failure => { const fieldPath = formatFailurePath(failure); const value = formatFailureValue(failure.value); return `Invalid argument "${fieldPath}", value: ${value}. ${failure.message}\n`; }); throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_VALIDATE_INPUT, { cause: error, message: formattedMessage.join(''), }); } }; } /** * Formats a full dotted path from failure, e.g. "command", "innerStruct.pubkey", "enumsArray[1]" */ function formatFailurePath(failure: Failure): string { const path = failure.path; if (!path || path.length === 0) return String(failure.key ?? ''); return path .map((segment, i) => { if (typeof segment === 'number') { return `[${segment}]`; } return `${i === 0 ? '' : '.'}${String(segment)}`; }) .join(''); } /** * Formats failure values for error messages, truncating long values and stringifying objects. */ const MAX_VALUE_LENGTH = 120; function formatFailureValue(value: unknown): string { const raw = typeof value === 'object' ? safeStringify(value) : String(value as unknown); return raw.length > MAX_VALUE_LENGTH ? `${raw.slice(0, MAX_VALUE_LENGTH)}...` : raw; } /** * Ensures that arguments with "omitted" defaultValueStrategy are not provided by the user (e.g. discriminator). */ function validateOmittedArguments(ixNode: InstructionNode, argumentsInput: ArgumentsInput = {}) { ixNode.arguments.filter(isOmittedArgument).forEach(ixArgumentNode => { if (Object.hasOwn(argumentsInput, ixArgumentNode.name)) { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_VALIDATE_INPUT, { message: 'Omitted argument must not be provided', }); } }); } function getRemainingAccountArgNames(ixNode: InstructionNode): string[] { return (ixNode.remainingAccounts ?? []) .filter(node => node.value.kind === 'argumentValueNode') .map(node => node.value.name); } /** * Filters out remaining account argument names from the arguments input. * So superstruct's object() doesn't reject them as extra keys. */ function filterRemainingAccountArguments(ixNode: InstructionNode, argumentsInput: ArgumentsInput): ArgumentsInput { const remainingAccountArgNames = getRemainingAccountArgNames(ixNode); if (!remainingAccountArgNames.length) { return argumentsInput; } const remainingAccountArgNamesSet = new Set(remainingAccountArgNames); return Object.fromEntries(Object.entries(argumentsInput).filter(([key]) => !remainingAccountArgNamesSet.has(key))); } ================================================ FILE: packages/dynamic-client/src/instruction-encoding/index.ts ================================================ // accounts export { createAccountMeta } from './accounts/create-account-meta'; export { createAccountsInputValidator } from './accounts/validate-accounts-input'; // arguments export { encodeInstructionArguments } from './arguments/encode-instruction-arguments'; export { createArgumentsInputValidator } from './arguments/validate-arguments-input'; export { resolveArgumentDefaultsFromCustomResolvers } from './arguments/resolve-argument-from-custom-resolvers'; // visitors export { ACCOUNT_DEFAULT_VALUE_SUPPORTED_NODE_KINDS, createAccountDefaultValueVisitor, } from './visitors/account-default-value'; export { createConditionNodeValueVisitor } from './visitors/condition-node-value'; export { createDefaultValueEncoderVisitor, DEFAULT_VALUE_ENCODER_SUPPORTED_NODE_KINDS, } from './visitors/default-value-encoder'; export { createInputValueTransformer, createInputValueTransformerVisitor } from './visitors/input-value-transformer'; export { createPdaSeedValueVisitor, PDA_SEED_VALUE_SUPPORTED_NODE_KINDS } from './visitors/pda-seed-value'; export { createValueNodeVisitor, VALUE_NODE_SUPPORTED_NODE_KINDS } from './visitors/value-node-value'; ================================================ FILE: packages/dynamic-client/src/instruction-encoding/instructions.ts ================================================ import { address } from '@solana/addresses'; import type { InstructionNode, RootNode } from 'codama'; import type { BuildIxFn } from '../shared/types'; import { createAccountMeta, createAccountsInputValidator } from './accounts'; import { createArgumentsInputValidator, encodeInstructionArguments, resolveArgumentDefaultsFromCustomResolvers, } from './arguments'; /** * Creates an instruction builder for a given InstructionNode. */ export function createIxBuilder(root: RootNode, ixNode: InstructionNode): BuildIxFn { const programAddress = address(root.program.publicKey); const validateArguments = createArgumentsInputValidator(root, ixNode); const validateAccounts = createAccountsInputValidator(ixNode); return async (argumentsInput, accountsInput, signers, resolversInput) => { // Validate arguments according to Codama schema. validateArguments(argumentsInput); // Ensure required accounts are present and validate provided pubkey addresses. validateAccounts(accountsInput); // Resolve arguments that depend on custom resolvers. const enrichedArgumentsInput = await resolveArgumentDefaultsFromCustomResolvers( ixNode, argumentsInput, accountsInput, resolversInput, ); // Encode arguments into buffer. const argumentsData = encodeInstructionArguments(root, ixNode, enrichedArgumentsInput); const accountsData = await createAccountMeta( root, ixNode, enrichedArgumentsInput, accountsInput, signers, resolversInput, ); return { accounts: accountsData, data: argumentsData, programAddress, }; }; } ================================================ FILE: packages/dynamic-client/src/instruction-encoding/resolvers/index.ts ================================================ export { resolveAccountAddress } from './resolve-account-address'; export { resolveAccountValueNodeAddress } from './resolve-account-value-node-address'; export { resolveConditionalValueNodeCondition } from './resolve-conditional'; export { resolvePDAAddress } from './resolve-pda-address'; export type { BaseResolutionContext, ResolutionPath } from './types'; ================================================ FILE: packages/dynamic-client/src/instruction-encoding/resolvers/resolve-account-address.ts ================================================ import { CODAMA_ERROR__DYNAMIC_CLIENT__ACCOUNT_MISSING, CODAMA_ERROR__DYNAMIC_CLIENT__INVARIANT_VIOLATION, CODAMA_ERROR__DYNAMIC_CLIENT__UNSUPPORTED_OPTIONAL_ACCOUNT_STRATEGY, CODAMA_ERROR__UNEXPECTED_NODE_KIND, CodamaError, } from '@codama/errors'; import type { Address } from '@solana/addresses'; import type { InstructionAccountNode, InstructionNode, RootNode } from 'codama'; import { visitOrElse } from 'codama'; import { type AddressInput, toAddress } from '../../shared/address'; import { safeStringify } from '../../shared/util'; import { ACCOUNT_DEFAULT_VALUE_SUPPORTED_NODE_KINDS, createAccountDefaultValueVisitor, } from '../visitors/account-default-value'; import type { BaseResolutionContext } from './types'; type ResolveAccountAddressContext = BaseResolutionContext & { accountAddressInput?: AddressInput | null | undefined; ixAccountNode: InstructionAccountNode; }; /** * Resolves the address of an instruction account node via either defaultValue or optionalAccountStrategy. */ export async function resolveAccountAddress({ root, ixNode, ixAccountNode, argumentsInput, accountsInput, resolutionPath, resolversInput, accountAddressInput, }: ResolveAccountAddressContext): Promise
{ // Optional accounts explicitly provided as null should be resolved based on optionalAccountStrategy if (accountAddressInput === null && ixAccountNode.isOptional) { return resolveOptionalAccountWithStrategy(root, ixNode, ixAccountNode); } if (ixAccountNode.defaultValue) { const visitor = createAccountDefaultValueVisitor({ accountAddressInput, accountsInput, argumentsInput, ixAccountNode, ixNode, resolutionPath, resolversInput, root, }); const addressValue = await visitOrElse(ixAccountNode.defaultValue, visitor, node => { throw new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, { expectedKinds: [...ACCOUNT_DEFAULT_VALUE_SUPPORTED_NODE_KINDS], kind: node.kind, node, }); }); // conditionalValueNode with ifFalse branch returns null. // This should be resolved via optionalAccountStrategy for optional accounts. if (addressValue === null && ixAccountNode.isOptional) { return resolveOptionalAccountWithStrategy(root, ixNode, ixAccountNode); } return addressValue; } throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__ACCOUNT_MISSING, { accountName: ixAccountNode.name, instructionName: ixNode.name, }); } /** * Optional account resolution via instruction strategy. * With "programId" strategy, optional accounts are resolved to programId. * With "omitted" strategy, optional accounts must be excluded from accounts list. */ function resolveOptionalAccountWithStrategy( root: RootNode, ixNode: InstructionNode, ixAccountNode: InstructionAccountNode, ) { if (!ixAccountNode.isOptional) { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__INVARIANT_VIOLATION, { message: `resolveOptionalAccountWithStrategy called for non-optional account: ${ixAccountNode.name}`, }); } switch (ixNode.optionalAccountStrategy) { case 'omitted': return null; case 'programId': return toAddress(root.program.publicKey); default: throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__UNSUPPORTED_OPTIONAL_ACCOUNT_STRATEGY, { accountName: ixAccountNode.name, instructionName: ixNode.name, strategy: safeStringify(ixNode.optionalAccountStrategy), }); } } ================================================ FILE: packages/dynamic-client/src/instruction-encoding/resolvers/resolve-account-value-node-address.ts ================================================ import { CODAMA_ERROR__DYNAMIC_CLIENT__CIRCULAR_ACCOUNT_DEPENDENCY, CODAMA_ERROR__DYNAMIC_CLIENT__NODE_REFERENCE_NOT_FOUND, CodamaError, } from '@codama/errors'; import type { Address } from '@solana/addresses'; import type { AccountValueNode } from 'codama'; import { toAddress } from '../../shared/address'; import { resolveAccountAddress } from './resolve-account-address'; import type { BaseResolutionContext, ResolutionPath } from './types'; /** * Resolves an AccountValueNode reference to an Address. * * Shared logic for resolving account references across visitors: * Checks if the user provided the account address in accountsInput. * Finds the referenced InstructionAccountNode. * Delegates to resolveAccountAddress for default value resolution. */ export async function resolveAccountValueNodeAddress( node: AccountValueNode, ctx: BaseResolutionContext, ): Promise
{ const { accountsInput, ixNode, resolutionPath } = ctx; // Check if user provided the account address. const providedAddress = accountsInput?.[node.name]; if (providedAddress !== undefined && providedAddress !== null) { return toAddress(providedAddress); } // Find the referenced account in the instruction. const referencedIxAccountNode = ixNode.accounts.find(acc => acc.name === node.name); if (!referencedIxAccountNode) { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__NODE_REFERENCE_NOT_FOUND, { instructionName: ixNode.name, referencedName: node.name, }); } // Detect circular dependencies before recursing. detectCircularDependency(node.name, resolutionPath); return await resolveAccountAddress({ accountAddressInput: providedAddress, accountsInput: ctx.accountsInput, argumentsInput: ctx.argumentsInput, ixAccountNode: referencedIxAccountNode, ixNode, resolutionPath: [...resolutionPath, node.name], resolversInput: ctx.resolversInput, root: ctx.root, }); } export function detectCircularDependency(nodeName: string, resolutionPath: ResolutionPath) { if (resolutionPath.includes(nodeName)) { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__CIRCULAR_ACCOUNT_DEPENDENCY, { chain: [...resolutionPath, nodeName].join(' -> '), }); } } ================================================ FILE: packages/dynamic-client/src/instruction-encoding/resolvers/resolve-conditional.ts ================================================ import { CODAMA_ERROR__DYNAMIC_CLIENT__INVARIANT_VIOLATION, CODAMA_ERROR__UNEXPECTED_NODE_KIND, CodamaError, } from '@codama/errors'; import type { ConditionalValueNode, InstructionAccountNode, InstructionInputValueNode } from 'codama'; import { isNode, visitOrElse } from 'codama'; import { getMaybeNodeKind } from '../../shared/util'; import { CONDITION_NODE_SUPPORTED_NODE_KINDS, createConditionNodeValueVisitor } from '../visitors/condition-node-value'; import { createValueNodeVisitor, VALUE_NODE_SUPPORTED_NODE_KINDS } from '../visitors/value-node-value'; import type { BaseResolutionContext } from './types'; export type ResolveConditionalContext = BaseResolutionContext & { conditionalValueNode: ConditionalValueNode; ixAccountNode: InstructionAccountNode; }; /** * Evaluates a ConditionalValueNode's condition. * Returns the matching branch (ifTrue or ifFalse) as an InstructionInputValueNode or undefined if no branch matches. */ export async function resolveConditionalValueNodeCondition({ root, ixNode, ixAccountNode, conditionalValueNode, argumentsInput, accountsInput, resolutionPath, resolversInput, }: ResolveConditionalContext): Promise { if (!isNode(conditionalValueNode, 'conditionalValueNode')) { throw new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, { expectedKinds: ['conditionalValueNode'], kind: getMaybeNodeKind(conditionalValueNode), node: conditionalValueNode, }); } const { condition, value: expectedValueNode, ifTrue, ifFalse } = conditionalValueNode; if (!expectedValueNode && !ifTrue && !ifFalse) { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__INVARIANT_VIOLATION, { message: `Invalid conditionalValueNode: missing value and branches for account ${ixAccountNode.name} in ${ixNode.name}`, }); } // Resolve the condition value of ConditionalValueNode. const conditionVisitor = createConditionNodeValueVisitor({ accountsInput, argumentsInput, ixNode, resolutionPath, resolversInput, root, }); const actualProvidedValue = await visitOrElse(condition, conditionVisitor, condNode => { throw new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, { expectedKinds: [...CONDITION_NODE_SUPPORTED_NODE_KINDS], kind: condNode.kind, node: condNode, }); }); if (!expectedValueNode) { return actualProvidedValue ? ifTrue : ifFalse; } // If expectedValueNode exists, the condition must be equal to expected value. const valueVisitor = createValueNodeVisitor(); const expectedValue = visitOrElse(expectedValueNode, valueVisitor, valueNode => { throw new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, { expectedKinds: [...VALUE_NODE_SUPPORTED_NODE_KINDS], kind: valueNode.kind, node: valueNode, }); }); if (typeof expectedValue.value === 'object' || typeof actualProvidedValue === 'object') { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__INVARIANT_VIOLATION, { message: 'Deep equality comparison not yet supported for conditional value', }); } return actualProvidedValue === expectedValue.value ? ifTrue : ifFalse; } ================================================ FILE: packages/dynamic-client/src/instruction-encoding/resolvers/resolve-pda-address.ts ================================================ import { CODAMA_ERROR__DYNAMIC_CLIENT__INVARIANT_VIOLATION, CODAMA_ERROR__DYNAMIC_CLIENT__NODE_REFERENCE_NOT_FOUND, CODAMA_ERROR__LINKED_NODE_NOT_FOUND, CODAMA_ERROR__UNEXPECTED_NODE_KIND, CODAMA_ERROR__UNRECOGNIZED_NODE_KIND, CodamaError, } from '@codama/errors'; import type { Address, ProgramDerivedAddress } from '@solana/addresses'; import { address, getProgramDerivedAddress } from '@solana/addresses'; import type { ReadonlyUint8Array } from '@solana/codecs'; import type { Node, PdaNode, PdaSeedValueNode, PdaValueNode, RegisteredPdaSeedNode, VariablePdaSeedNode } from 'codama'; import { isNode, visitOrElse } from 'codama'; import { getMaybeNodeKind } from '../../shared/util'; import { createPdaSeedValueVisitor, PDA_SEED_VALUE_SUPPORTED_NODE_KINDS } from '../visitors/pda-seed-value'; import type { BaseResolutionContext } from './types'; export type ResolvePDAAddressContext = BaseResolutionContext & { pdaValueNode: PdaValueNode; }; /** * Derives a PDA from a PdaValueNode. * Encodes each seed (ConstantPdaSeedNode and VariablePdaSeedNode) into bytes and computes the address. */ export async function resolvePDAAddress({ root, ixNode, argumentsInput = {}, accountsInput = {}, pdaValueNode, resolutionPath, resolversInput, }: ResolvePDAAddressContext): Promise { if (!isNode(pdaValueNode, 'pdaValueNode')) { throw new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, { expectedKinds: ['pdaValueNode'], kind: getMaybeNodeKind(pdaValueNode), node: pdaValueNode, }); } const pdaNode = resolvePdaNode(pdaValueNode, root.program.pdas); const programId = address(pdaNode.programId || root.program.publicKey); const seedValues = await Promise.all( pdaNode.seeds.map(async seedNode => { if (seedNode.kind === 'constantPdaSeedNode') { return await resolveConstantPdaSeed({ accountsInput, argumentsInput, ixNode, programId, resolutionPath, resolversInput, root, seedNode, }); } if (seedNode.kind === 'variablePdaSeedNode') { const variableSeedValueNodes = pdaValueNode.seeds; const seedName = seedNode.name; const variableSeedValueNode = variableSeedValueNodes.find(node => node.name === seedName); if (!variableSeedValueNode) { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__NODE_REFERENCE_NOT_FOUND, { instructionName: ixNode.name, referencedName: seedName, }); } return await resolveVariablePdaSeed({ accountsInput, argumentsInput, ixNode, programId, resolutionPath, resolversInput, root, seedNode, variableSeedValueNode, }); } throw new CodamaError(CODAMA_ERROR__UNRECOGNIZED_NODE_KIND, { kind: getMaybeNodeKind(seedNode) ?? 'unknown', }); }), ); return await getProgramDerivedAddress({ programAddress: programId, seeds: seedValues, }); } function resolvePdaNode(pdaDefaultValue: PdaValueNode, pdas: PdaNode[]): PdaNode { if (isNode(pdaDefaultValue.pda, 'pdaLinkNode')) { const linkedPda = pdas.find(p => p.name === pdaDefaultValue.pda.name); if (!linkedPda) { throw new CodamaError(CODAMA_ERROR__LINKED_NODE_NOT_FOUND, { kind: 'pdaLinkNode', linkNode: pdaDefaultValue.pda, name: pdaDefaultValue.pda.name, path: [], }); } return linkedPda; } if (isNode(pdaDefaultValue.pda, 'pdaNode')) { return pdaDefaultValue.pda; } throw new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, { expectedKinds: ['pdaLinkNode', 'pdaNode'], kind: getMaybeNodeKind(pdaDefaultValue.pda), node: pdaDefaultValue.pda, }); } type ResolvePdaSeedContext = BaseResolutionContext & { programId: Address; seedNode: VariablePdaSeedNode; variableSeedValueNode: PdaSeedValueNode; }; function resolveVariablePdaSeed({ accountsInput = {}, argumentsInput = {}, ixNode, programId, resolutionPath, resolversInput, root, seedNode, variableSeedValueNode, }: ResolvePdaSeedContext): Promise { if (!isNode(variableSeedValueNode, 'pdaSeedValueNode')) { throw new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, { expectedKinds: ['pdaSeedValueNode'], kind: getMaybeNodeKind(variableSeedValueNode), node: variableSeedValueNode as Node, }); } if (seedNode.name !== variableSeedValueNode.name) { // Sanity check: this should not happen. throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__INVARIANT_VIOLATION, { message: `Mismatched PDA seed names: expected [${seedNode.name}], got [${variableSeedValueNode.name}]`, }); } const visitor = createPdaSeedValueVisitor({ accountsInput, argumentsInput, ixNode, programId, resolutionPath, resolversInput, root, seedTypeNode: seedNode.type, }); return visitOrElse(variableSeedValueNode.value, visitor, node => { throw new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, { expectedKinds: [...PDA_SEED_VALUE_SUPPORTED_NODE_KINDS], kind: node.kind, node, }); }); } type ResolveConstantPdaSeedContext = BaseResolutionContext & { programId: Address; seedNode: RegisteredPdaSeedNode; }; function resolveConstantPdaSeed({ accountsInput, argumentsInput, ixNode, programId, resolutionPath, resolversInput, root, seedNode, }: ResolveConstantPdaSeedContext): Promise { if (!isNode(seedNode, 'constantPdaSeedNode')) { throw new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, { expectedKinds: ['constantPdaSeedNode'], kind: seedNode.kind, node: seedNode, }); } const visitor = createPdaSeedValueVisitor({ accountsInput, argumentsInput, ixNode, programId, resolutionPath, resolversInput, root, seedTypeNode: seedNode.type, }); return visitOrElse(seedNode.value, visitor, node => { throw new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, { expectedKinds: [...PDA_SEED_VALUE_SUPPORTED_NODE_KINDS], kind: node.kind, node, }); }); } ================================================ FILE: packages/dynamic-client/src/instruction-encoding/resolvers/types.ts ================================================ import type { InstructionNode, RootNode } from 'codama'; import type { AccountsInput, ArgumentsInput, ResolversInput } from '../../shared/types'; // Array of node names being resolved to detect circular dependencies. export type ResolutionPath = readonly string[]; /** * Shared context threaded through the account/PDA resolution pipeline. * Individual resolvers/visitors extend this with domain-specific fields. */ export type BaseResolutionContext = { accountsInput: AccountsInput | undefined; argumentsInput: ArgumentsInput | undefined; ixNode: InstructionNode; resolutionPath: ResolutionPath; resolversInput: ResolversInput | undefined; root: RootNode; }; ================================================ FILE: packages/dynamic-client/src/instruction-encoding/validators.ts ================================================ import { isAddress } from '@solana/addresses'; import type { ArrayTypeNode, CountNode, DefinedTypeNode, EnumVariantTypeNode, InstructionAccountNode, InstructionArgumentNode, SetTypeNode, TypeNode, } from 'codama'; import { array, boolean, define, intersection, number, object, size, string, Struct, StructError, tuple, } from 'superstruct'; import { isPublicKeyLike } from '../shared/address'; import { getMemoizedUtf8Encoder } from '../shared/codecs'; import { formatValueType, getMaybeNodeKind, safeStringify } from '../shared/util'; type StructUnknown = Struct; /** * Creates a superstruct validator for InstructionAccountNodes. * * if node is optional, then validate only if it's provided. * if node has defaultValue, then consider it as optional and validate only if it's provided because it will be resolved from defaultValue. */ export function createIxAccountsValidator(ixAccountNodes: InstructionAccountNode[]): StructUnknown { const shape = ixAccountNodes.reduce>((acc, node) => { acc[node.name] = node.isOptional || node.defaultValue ? OptionalSolanaAddressValidator : SolanaAddressValidator; return acc; }, {}); return object(shape) as StructUnknown; } /** * Creates a superstruct validator for instruction InstructionArgumentNodes. */ export function createIxArgumentsValidator( ixNodeName: string, ixArgumentNodes: InstructionArgumentNode[], definedTypes: DefinedTypeNode[], ): StructUnknown { const shape = ixArgumentNodes.reduce>((acc, argumentNode, index) => { if (!argumentNode.type) { throw new Error(`Argument ${argumentNode.name} of instruction ${ixNodeName} does not have a type`); } acc[argumentNode.name] = createValidatorForTypeNode( `${ixNodeName}_${argumentNode.name}_${index}`, argumentNode.type, definedTypes, ); return acc; }, {}); return object(shape) as StructUnknown; } function createValidatorForTypeNode(nodeName: string, node: TypeNode, definedTypes: DefinedTypeNode[]): StructUnknown { if (!node) { throw new Error( `Node ${nodeName} is not defined. ${definedTypes.length} defined types were provided: ${definedTypes.map(t => t.name).join(', ')}`, ); } switch (node.kind) { case 'arrayTypeNode': { return ArrayValidator(`${nodeName}_array`, node, definedTypes); } case 'booleanTypeNode': { return boolean() as StructUnknown; } case 'numberTypeNode': { const format = node.format; if (format === 'u64' || format === 'u128' || format === 'i64' || format === 'i128') { return NumberOrBigintValidator; } return number() as StructUnknown; } case 'publicKeyTypeNode': { return SolanaAddressValidator; } case 'setTypeNode': { // array of unique items return intersection([ UniqueItemsValidator, ArrayValidator(`${nodeName}_set`, node, definedTypes), ]) as StructUnknown; } case 'stringTypeNode': { return string() as StructUnknown; } case 'fixedSizeTypeNode': { // fixedSizeTypeNode wraps an inner type and constrains its byte size if (node.type.kind === 'stringTypeNode') { // For fixed-size strings, validate that UTF-8 bytes fit within the size return StringValidatorForFixedSize(node.size); } if (node.type.kind === 'bytesTypeNode') { // For fixed-size bytes, validate exact byte length return BytesWithSizeValidator(node.size); } // For other types, delegate to the inner type validator // The size constraint is handled during encoding return createValidatorForTypeNode(`${nodeName}_fixed_size`, node.type, definedTypes); } case 'bytesTypeNode': { return BytesLikeValidator; } case 'dateTimeTypeNode': { return createValidatorForTypeNode(`${nodeName}_date_time`, node.number, definedTypes); } case 'definedTypeLinkNode': { const definedType = definedTypes.find(d => d.name === node.name); if (!definedType) { throw new Error(`Undefined type: ${node.name} ${node.kind}`); } return createValidatorForTypeNode(`${nodeName}_defined_type`, definedType.type, definedTypes); } case 'mapTypeNode': { const keyValidator = createValidatorForTypeNode( `${nodeName}_map_key_${node.key.kind}`, node.key, definedTypes, ); const valueValidator = createValidatorForTypeNode( `${nodeName}_map_value_${node.value.kind}`, node.value, definedTypes, ); const sizeValidator = MapCountValidator(node.count); const keyValueValidator = KeyValueValidator(nodeName, keyValidator, valueValidator); if (sizeValidator) { return intersection([keyValueValidator, sizeValidator]) as StructUnknown; } return keyValueValidator; } case 'structTypeNode': { const structShape = node.fields.reduce>((acc, field) => { acc[field.name] = createValidatorForTypeNode( `${nodeName}_struct_${field.name}`, field.type, definedTypes, ); return acc; }, {}); return object(structShape) as StructUnknown; } case 'tupleTypeNode': { const validators = node.items.map((typeNode, index) => createValidatorForTypeNode(`${nodeName}_tuple${typeNode.kind}_${index}`, typeNode, definedTypes), ); return tuple(validators as [StructUnknown, ...StructUnknown[]]) as StructUnknown; } case 'zeroableOptionTypeNode': { const innerValidator = createValidatorForTypeNode( `${nodeName}_zeroable_option_item`, node.item, definedTypes, ); return ZeroableOptionValidator(`${nodeName}_zeroable_option`, innerValidator); } case 'optionTypeNode': { // TODO: Do we need to validate node.fixed and node.prefix of OptionTypeNode? const SomeValueValidator = createValidatorForTypeNode(`${nodeName}_option_item`, node.item, definedTypes); return OptionValueValidator(`${nodeName}_option`, SomeValueValidator); } case 'remainderOptionTypeNode': { const innerValidator = RemainderOptionTypeItemValidator( `${nodeName}_remainder_option_item`, node.item, definedTypes, ); return OptionValueValidator(`${nodeName}_remainder_option`, innerValidator); } case 'hiddenPrefixTypeNode': case 'hiddenSuffixTypeNode': case 'sentinelTypeNode': case 'postOffsetTypeNode': case 'preOffsetTypeNode': case 'sizePrefixTypeNode': { return createValidatorForTypeNode(`${nodeName}_size_prefix`, node.type, definedTypes); } case 'enumTypeNode': { return EnumVariantValidator(nodeName, node.variants, definedTypes); } case 'amountTypeNode': { return AmountTypeValidator(nodeName); } case 'solAmountTypeNode': { return AmountTypeValidator(nodeName); } default: { node['kind'] satisfies never; throw new Error(`Validator for TypeNode "${nodeName}" kind: ${getMaybeNodeKind(node)} is not implemented!`); } } } function RemainderOptionTypeItemValidator( nodeName: string, itemNode: TypeNode, definedTypes: DefinedTypeNode[], ): StructUnknown { if (itemNode.kind === 'fixedSizeTypeNode' && itemNode.type.kind === 'stringTypeNode') { // For fixed-size strings in remainder options, accept any string return StringValidatorForFixedSize(itemNode.size); } if (itemNode.kind === 'definedTypeLinkNode') { const definedType = definedTypes.find(d => d.name === itemNode.name); if (definedType?.type.kind === 'fixedSizeTypeNode' && definedType.type.type.kind === 'stringTypeNode') { return StringValidatorForFixedSize(definedType.type.size); } } return createValidatorForTypeNode(nodeName, itemNode, definedTypes); } function StringValidatorForFixedSize(maxSize: number): StructUnknown { return define(`StringForFixedSize_max_${maxSize}`, (value: unknown) => { if (typeof value !== 'string') { return `Expected a string, received: ${formatValueType(value)}`; } const encoder = getMemoizedUtf8Encoder(); const bytes = encoder.encode(value); return ( bytes.length <= maxSize || `String exceeds max size: ${bytes.length} bytes (UTF-8), limit is ${maxSize} bytes` ); }) as StructUnknown; } /** * Validator for enum variants. * Handles both scalar enums and enums with data. */ function EnumVariantValidator( nodeName: string, variants: EnumVariantTypeNode[], definedTypes: DefinedTypeNode[], ): StructUnknown { const variantMap = new Map(variants.map(v => [v.name, v])); const variantNames = Array.from(variantMap.keys()); // Eagerly build per-variant payload validators for struct and tuple variants const variantValidators = new Map(); for (const variant of variants) { if (variant.kind === 'enumStructVariantTypeNode') { variantValidators.set( variant.name, createValidatorForTypeNode(`${nodeName}_${variant.name}`, variant.struct, definedTypes), ); } else if (variant.kind === 'enumTupleVariantTypeNode') { variantValidators.set( variant.name, createValidatorForTypeNode(`${nodeName}_${variant.name}`, variant.tuple, definedTypes), ); } } return define(`${nodeName}_EnumVariant`, (value: unknown) => { // Scalar enum: plain string variant name (e.g. 'foo', 'bar') if (typeof value === 'string') return ( variantMap.has(value) || `Invalid enum value "${value}". Expected one of: ${variantNames.join(', ')}` ); // Data enum variant: object with __kind (e.g. { __kind: 'tokenTransfer', amount: 1000 }) if (typeof value === 'object' && value !== null && '__kind' in value) { const kind = (value as Record)['__kind']; if (typeof kind !== 'string') { return `Expected __kind to be a string, received: ${formatValueType(kind)}`; } const variant = variantMap.get(kind); if (!variant) { return `Invalid enum variant "${kind}". Expected one of: ${variantNames.join(', ')}`; } if (variant.kind === 'enumEmptyVariantTypeNode') { return true; } // Validations of enum payloads // eslint-disable-next-line @typescript-eslint/no-unused-vars const { __kind: _, ...rest } = value as Record; const payloadValidator = variantValidators.get(kind); if (!payloadValidator) { return true; } if (variant.kind === 'enumStructVariantTypeNode') { const [structError] = payloadValidator.validate(rest); return structError ? formatErrorForEnumTypeNode(kind, structError) : true; } if (variant.kind === 'enumTupleVariantTypeNode') { const fields = (rest as { fields?: unknown }).fields; const [structError] = payloadValidator.validate(fields); return structError ? formatErrorForEnumTypeNode(kind, structError) : true; } } return `Expected an enum variant (string or object with __kind), received: ${formatValueType(value)}`; }) as StructUnknown; } function formatErrorForEnumTypeNode(enumVariantKind: string, error: StructError) { const failures = error.failures(); const first = failures?.[0]; if (first) { return `Enum variant "${enumVariantKind}" has invalid "${String(first.key)}"`; } return `Enum variant "${enumVariantKind}" has invalid payload`; } const SolanaAddressValidator: StructUnknown = /* @__PURE__ */ define('SolanaAddress', (value: unknown) => { if (typeof value === 'string') { return isAddress(value) || `Expected a valid Solana address (base58), received string: "${value}"`; } if (isPublicKeyLike(value)) { return isAddress(value.toBase58()) || 'Expected a valid Solana address, received an invalid PublicKey'; } return `Expected a Solana address (base58 string or PublicKey), received: ${formatValueType(value)}`; }); const OptionalSolanaAddressValidator: StructUnknown = /* @__PURE__ */ define( 'OptionalSolanaAddress', (value: unknown) => { if (value === undefined || value === null) return true; const [error] = SolanaAddressValidator.validate(value); if (!error) return true; return error.failures()[0]?.message ?? 'Expected a valid Solana address or null/undefined'; }, ); const NumberOrBigintValidator: StructUnknown = /* @__PURE__ */ define('NumberOrBigint', (value: unknown) => { if (typeof value === 'number') { return Number.isSafeInteger(value) || `Expected a safe integer, received unsafe number: ${value}`; } if (typeof value === 'bigint') return true; return `Expected a number or bigint, received: ${formatValueType(value)}`; }); const BytesLikeValidator: StructUnknown = /* @__PURE__ */ define('BytesLike', (value: unknown) => { if (value instanceof Uint8Array) return true; if (!Array.isArray(value)) { return `Expected a Uint8Array or number[] (bytes 0-255), received: ${formatValueType(value)}`; } const invalidIndex = value.findIndex(n => typeof n !== 'number' || !Number.isInteger(n) || n < 0 || n > 255); if (invalidIndex !== -1) { return `Expected byte values (integers 0-255), invalid element at index ${invalidIndex}: ${String(value[invalidIndex])}`; } return true; }); /** * Validator for bytes that must be exactly a specific size. * Used for fixedSizeTypeNode wrapping bytesTypeNode. */ function BytesWithSizeValidator(exactSize: number): StructUnknown { return define(`BytesWithSize_${exactSize}`, (value: unknown) => { if (value instanceof Uint8Array) { return value.length === exactSize || `Expected exactly ${exactSize} bytes, received ${value.length} bytes`; } if (!Array.isArray(value)) { return `Expected a Uint8Array or number[] of exactly ${exactSize} bytes, received: ${formatValueType(value)}`; } if (value.length !== exactSize) { return `Expected exactly ${exactSize} bytes, received ${value.length} elements`; } const invalidIndex = value.findIndex(n => typeof n !== 'number' || !Number.isInteger(n) || n < 0 || n > 255); if (invalidIndex !== -1) { return `Expected byte values (integers 0-255), invalid element at index ${invalidIndex}: ${String(value[invalidIndex])}`; } return true; }) as StructUnknown; } // Validates value only if it is not null or undefined (i.e. if it's provided). // SomeValueValidator validates the provided value (i.e. Some(value)). function OptionValueValidator(name: string, SomeValueValidator: StructUnknown): StructUnknown { return define(`${name}_OptionValueValidator`, (value: unknown) => { if (value === null || value === undefined) return true; const [error] = SomeValueValidator.validate(value); if (!error) return true; return error.failures()[0]?.message ?? 'Invalid value for optional field'; }) as StructUnknown; } // Validates zeroable option: null is valid, otherwise validates the inner validator. function ZeroableOptionValidator(name: string, innerValidator: StructUnknown): StructUnknown { return define(name, (value: unknown) => { if (value == null) return true; const [error] = innerValidator.validate(value); if (!error) return true; return error.failures()[0]?.message ?? 'Expected a valid value or null for zeroable option'; }) as StructUnknown; } // Checks that all items in the array are unique. const UniqueItemsValidator: StructUnknown = /* @__PURE__ */ define('UniqueItems', (value: unknown) => { if (!Array.isArray(value)) { return `Expected an array with unique items, received: ${formatValueType(value)}`; } const unique = new Map(); for (let i = 0; i < value.length; i++) { const key = safeStringify(value[i]); const index = unique.get(key); if (index !== undefined) { return `Expected all items to be unique, found duplicate at indices ${index} and ${i}`; } unique.set(key, i); } return true; }) as StructUnknown; // Validates every key of an object according to KeyValidator. // Validates every value of an object according to ValueValidator. // Used in MapTypeNode, where the keys and values are of the same type. function KeyValueValidator(name: string, KeyValidator: StructUnknown, ValueValidator: StructUnknown): StructUnknown { return define(`${name}_KeyValueValidator`, (value: unknown) => { if (typeof value !== 'object' || value === null) { return `Expected a map (object), received: ${formatValueType(value)}`; } const record = value as Record; const invalidKeys: string[] = []; const invalidValues: string[] = []; for (const key of Object.keys(record)) { if (KeyValidator.validate(key)[0]) invalidKeys.push(key); if (ValueValidator.validate(record[key])[0]) invalidValues.push(key); } if (!invalidKeys.length && !invalidValues.length) return true; const parts: string[] = []; if (invalidKeys.length) parts.push(`invalid keys: ${invalidKeys.join(', ')}`); if (invalidValues.length) parts.push(`invalid values: ${invalidValues.join(', ')}`); return `Map validation failed: ${parts.join('; ')}`; }) as StructUnknown; } function MapCountValidator(node: CountNode): StructUnknown | null { switch (node.kind) { case 'fixedCountNode': return KeysLengthValidator(node.value); case 'remainderCountNode': case 'prefixedCountNode': return null; // the number of items is unknown or arbitrary, like vec![] default: throw new Error(`Unsupported map count type: ${getMaybeNodeKind(node)}`); } } // Validates the number of keys in an object // Can be used in MapTypeNode with "fixed" CountNode type function KeysLengthValidator(count: number): StructUnknown { return define(`KeysLengthValidator_len_${count}`, (value: unknown) => { if (typeof value !== 'object' || value === null) { return `Expected a map with exactly ${count} entries, received: ${formatValueType(value)}`; } const actual = Object.keys(value).length; return actual === count || `Expected exactly ${count} map entries, received ${actual}`; }) as StructUnknown; } // Handles both fixed-size and variable-size arrays function ArrayValidator( nodeName: string, node: ArrayTypeNode | SetTypeNode, definedTypes: DefinedTypeNode[], ): StructUnknown { // First define a validator for every array item const itemValidator = createValidatorForTypeNode(nodeName, node.item, definedTypes); // Then validate CountNode representing array size: // https://github.com/codama-idl/codama/blob/main/packages/nodes/docs/typeNodes/ArrayTypeNode.md switch (node.count.kind) { case 'fixedCountNode': { return size(array(itemValidator), node.count.value) as StructUnknown; } case 'remainderCountNode': case 'prefixedCountNode': { return array(itemValidator) as StructUnknown; } default: { // This should be unreachable with the current `CountNode` union but helps // guard against future Codama expansions. throw new Error(`Node: ${nodeName}. Unsupported array count type`); } } } /** * Validator for amountTypeNode and solAmountTypeNode. * Accepts number, bigint. */ function AmountTypeValidator(nodeName: string): StructUnknown { return define(`AmountType_${nodeName}`, (value: unknown) => { if (typeof value === 'number') { return Number.isSafeInteger(value) || `Expected a safe integer, received unsafe number: ${value}`; } if (typeof value === 'bigint') { return true; } return `Expected a number or bigint, received: ${formatValueType(value)}`; }) as StructUnknown; } ================================================ FILE: packages/dynamic-client/src/instruction-encoding/visitors/account-default-value.ts ================================================ import { CODAMA_ERROR__DYNAMIC_CLIENT__ACCOUNT_MISSING, CODAMA_ERROR__DYNAMIC_CLIENT__ACCOUNT_RESOLVER_MISSING, CODAMA_ERROR__DYNAMIC_CLIENT__ARGUMENT_MISSING, CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_DERIVE_PDA, CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_EXECUTE_RESOLVER, CODAMA_ERROR__DYNAMIC_CLIENT__INVALID_ACCOUNT_ADDRESS, CODAMA_ERROR__DYNAMIC_CLIENT__UNEXPECTED_ADDRESS_TYPE, CODAMA_ERROR__DYNAMIC_CLIENT__UNSUPPORTED_NODE, CODAMA_ERROR__UNEXPECTED_NODE_KIND, CodamaError, } from '@codama/errors'; import type { Address } from '@solana/addresses'; import { address } from '@solana/addresses'; import type { Visitor } from 'codama'; import type { AccountBumpValueNode, AccountValueNode, ArgumentValueNode, ConditionalValueNode, IdentityValueNode, InstructionAccountNode, PayerValueNode, PdaValueNode, ProgramIdValueNode, PublicKeyValueNode, ResolverValueNode, } from 'codama'; import { visitOrElse } from 'codama'; import type { AddressInput } from '../../shared/address'; import { isConvertibleAddress, toAddress } from '../../shared/address'; import { formatValueType, safeStringify } from '../../shared/util'; import { resolveAccountValueNodeAddress } from '../resolvers/resolve-account-value-node-address'; import { resolveConditionalValueNodeCondition } from '../resolvers/resolve-conditional'; import { resolvePDAAddress } from '../resolvers/resolve-pda-address'; import type { BaseResolutionContext } from '../resolvers/types'; type AccountDefaultValueVisitorContext = BaseResolutionContext & { accountAddressInput: AddressInput | null | undefined; ixAccountNode: InstructionAccountNode; }; export const ACCOUNT_DEFAULT_VALUE_SUPPORTED_NODE_KINDS = [ 'accountBumpValueNode', 'accountValueNode', 'argumentValueNode', 'conditionalValueNode', 'identityValueNode', 'payerValueNode', 'pdaValueNode', 'programIdValueNode', 'publicKeyValueNode', 'resolverValueNode', ] as const; type AccountDefaultValueSupportedNodeKind = (typeof ACCOUNT_DEFAULT_VALUE_SUPPORTED_NODE_KINDS)[number]; /** * Visitor for resolving InstructionInputValueNode types to Address values for account resolution. */ export function createAccountDefaultValueVisitor( ctx: AccountDefaultValueVisitorContext, ): Visitor, AccountDefaultValueSupportedNodeKind> { const { root, ixNode, ixAccountNode, accountAddressInput, argumentsInput, accountsInput, resolversInput, resolutionPath, } = ctx; return { visitAccountBumpValue: async (_node: AccountBumpValueNode) => { return await Promise.reject( new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__UNSUPPORTED_NODE, { nodeKind: 'accountBumpValueNode', }), ); }, visitAccountValue: async (node: AccountValueNode) => { return await resolveAccountValueNodeAddress(node, { accountsInput, argumentsInput, ixNode, resolutionPath, resolversInput, root, }); }, visitArgumentValue: async (node: ArgumentValueNode) => { const argValue = argumentsInput?.[node.name]; if (argValue === undefined || argValue === null) { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__ARGUMENT_MISSING, { argumentName: node.name, instructionName: ixNode.name, }); } if (!isConvertibleAddress(argValue)) { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__UNEXPECTED_ADDRESS_TYPE, { accountName: ixAccountNode.name, actualType: formatValueType(argValue), expectedType: 'Address | PublicKey', }); } return await Promise.resolve(toAddress(argValue)); }, visitConditionalValue: async (conditionalValueNode: ConditionalValueNode) => { // ifTrue or ifFalse branch of ConditionalValueNode. const resolvedInputValueNode = await resolveConditionalValueNodeCondition({ accountsInput, argumentsInput, conditionalValueNode, ixAccountNode, ixNode, resolutionPath, resolversInput, root, }); if (resolvedInputValueNode === undefined) { // No matching branch (e.g. conditional with no ifFalse and falsy condition). // Return null to signal "unresolved" to apply optionalAccountStrategy. if (ixAccountNode.isOptional) { return null; } throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__ACCOUNT_MISSING, { accountName: ixAccountNode.name, instructionName: ixNode.name, }); } // Recursively resolve the chosen branch. const visitor = createAccountDefaultValueVisitor(ctx); const addressValue = await visitOrElse(resolvedInputValueNode, visitor, innerNode => { throw new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, { expectedKinds: [...ACCOUNT_DEFAULT_VALUE_SUPPORTED_NODE_KINDS], kind: innerNode.kind, node: innerNode, }); }); return addressValue; }, visitIdentityValue: async (_node: IdentityValueNode) => { if (accountAddressInput === undefined || accountAddressInput === null) { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__ACCOUNT_MISSING, { accountName: ixAccountNode.name, instructionName: ixNode.name, }); } return await Promise.resolve(toAddress(accountAddressInput)); }, visitPayerValue: async (_node: PayerValueNode) => { if (accountAddressInput === undefined || accountAddressInput === null) { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__ACCOUNT_MISSING, { accountName: ixAccountNode.name, instructionName: ixNode.name, }); } return await Promise.resolve(toAddress(accountAddressInput)); }, visitPdaValue: async (node: PdaValueNode) => { const pda = await resolvePDAAddress({ accountsInput, argumentsInput, ixNode, pdaValueNode: node, resolutionPath, resolversInput, root, }); if (pda === null) { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_DERIVE_PDA, { accountName: ixAccountNode.name, }); } return pda[0]; }, visitProgramIdValue: async (_node: ProgramIdValueNode) => { return await Promise.resolve(address(root.program.publicKey)); }, visitPublicKeyValue: async (node: PublicKeyValueNode) => { return await Promise.resolve(address(node.publicKey)); }, visitResolverValue: async (node: ResolverValueNode) => { const resolverFn = resolversInput?.[node.name]; if (!resolverFn) { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__ACCOUNT_RESOLVER_MISSING, { accountName: ixAccountNode.name, resolverName: node.name, }); } let result: unknown; try { result = await resolverFn(argumentsInput ?? {}, accountsInput ?? {}); } catch (error) { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_EXECUTE_RESOLVER, { cause: error, resolverName: node.name, targetKind: 'instructionAccountNode', targetName: ixAccountNode.name, }); } if (!isConvertibleAddress(result)) { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__INVALID_ACCOUNT_ADDRESS, { accountName: ixAccountNode.name, value: safeStringify(result), }); } return toAddress(result); }, }; } ================================================ FILE: packages/dynamic-client/src/instruction-encoding/visitors/condition-node-value.ts ================================================ import { CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_EXECUTE_RESOLVER, CodamaError } from '@codama/errors'; import type { Visitor } from 'codama'; import type { AccountValueNode, ArgumentValueNode, ResolverValueNode } from 'codama'; import { resolveAccountValueNodeAddress } from '../resolvers/resolve-account-value-node-address'; import type { BaseResolutionContext } from '../resolvers/types'; export const CONDITION_NODE_SUPPORTED_NODE_KINDS = [ 'accountValueNode', 'argumentValueNode', 'resolverValueNode', ] as const; type ConditionNodeSupportedNodeKind = (typeof CONDITION_NODE_SUPPORTED_NODE_KINDS)[number]; /** * Visitor for resolving condition nodes in ConditionalValueNode. * Returns the runtime value of the condition (from accounts or arguments). */ export function createConditionNodeValueVisitor( ctx: BaseResolutionContext, ): Visitor, ConditionNodeSupportedNodeKind> { const { root, ixNode, argumentsInput, accountsInput, resolutionPath, resolversInput } = ctx; return { visitAccountValue: async (node: AccountValueNode) => { // If the user explicitly provides null for a conditional account, // return it for the conditionalValueNode ifFalse branch. const accountAddressInput = accountsInput?.[node.name]; if (accountAddressInput === null) { return null; } return await resolveAccountValueNodeAddress(node, { accountsInput, argumentsInput, ixNode, resolutionPath, resolversInput, root, }); }, visitArgumentValue: async (node: ArgumentValueNode) => { const argInput = argumentsInput?.[node.name]; return await Promise.resolve(argInput); }, visitResolverValue: async (node: ResolverValueNode) => { const resolverFn = resolversInput?.[node.name]; if (!resolverFn) { // ConditionalValueNode evaluates condition and based on result it chooses to take either ifTrue or ifFalse branch. // If resolver is not provided, we assume condition is false and return undefined instead of throwing an error to take ifFalse branch. return undefined; } try { return await resolverFn(argumentsInput ?? {}, accountsInput ?? {}); } catch (error) { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_EXECUTE_RESOLVER, { cause: error, resolverName: node.name, targetKind: 'conditionalValueNode', targetName: node.name, }); } }, }; } ================================================ FILE: packages/dynamic-client/src/instruction-encoding/visitors/default-value-encoder.ts ================================================ import type { ReadonlyUint8Array } from '@solana/codecs'; import type { Visitor } from 'codama'; import type { BooleanValueNode, BytesValueNode, EnumValueNode, NumberValueNode, PublicKeyValueNode, StringValueNode, } from 'codama'; export const DEFAULT_VALUE_ENCODER_SUPPORTED_NODE_KINDS = [ 'booleanValueNode', 'bytesValueNode', 'enumValueNode', 'noneValueNode', 'numberValueNode', 'publicKeyValueNode', 'stringValueNode', ] as const; type DefaultValueEncoderSupportedNodeKind = (typeof DEFAULT_VALUE_ENCODER_SUPPORTED_NODE_KINDS)[number]; /** * Visitor for encoding default (omitted) values for instruction arguments. * * Today, Anchor/Codama primarily uses omitted defaults for discriminators * (`bytesValueNode`), but this visitor is intentionally extensible as we * expand node coverage over time. */ export function createDefaultValueEncoderVisitor(codec: { encode: (value: unknown) => ReadonlyUint8Array; }): Visitor { return { visitBooleanValue: (node: BooleanValueNode) => codec.encode(node.boolean), visitBytesValue: (node: BytesValueNode) => codec.encode([node.encoding, node.data]), visitEnumValue: (node: EnumValueNode) => codec.encode(node.variant), visitNoneValue: () => codec.encode(null), visitNumberValue: (node: NumberValueNode) => codec.encode(node.number), visitPublicKeyValue: (node: PublicKeyValueNode) => codec.encode(node.publicKey), visitStringValue: (node: StringValueNode) => codec.encode(node.string), }; } ================================================ FILE: packages/dynamic-client/src/instruction-encoding/visitors/index.ts ================================================ export { createAccountDefaultValueVisitor } from './account-default-value'; export { createConditionNodeValueVisitor } from './condition-node-value'; export { createDefaultValueEncoderVisitor, DEFAULT_VALUE_ENCODER_SUPPORTED_NODE_KINDS } from './default-value-encoder'; export { createPdaSeedValueVisitor } from './pda-seed-value'; export { createValueNodeVisitor } from './value-node-value'; export { createInputValueTransformer, createInputValueTransformerVisitor } from './input-value-transformer'; ================================================ FILE: packages/dynamic-client/src/instruction-encoding/visitors/input-value-transformer.ts ================================================ import { CODAMA_ERROR__DYNAMIC_CLIENT__UNEXPECTED_ARGUMENT_TYPE, CODAMA_ERROR__LINKED_NODE_NOT_FOUND, CODAMA_ERROR__UNEXPECTED_NODE_KIND, CodamaError, } from '@codama/errors'; import type { BytesEncoding, Node, RootNode, TypeNode, Visitor } from 'codama'; import { isNode, pascalCase, visitOrElse } from 'codama'; import { isUint8Array, uint8ArrayToEncodedString } from '../../shared/bytes-encoding'; import { formatValueType, isObjectRecord } from '../../shared/util'; /** * Type nodes that the input value transformer can process. * Includes all StandaloneTypeNode kinds plus definedTypeLinkNode. */ export const INPUT_VALUE_TRANSFORMER_SUPPORTED_NODE_KINDS = [ 'amountTypeNode', 'arrayTypeNode', 'booleanTypeNode', 'bytesTypeNode', 'dateTimeTypeNode', 'definedTypeLinkNode', 'enumTypeNode', 'fixedSizeTypeNode', 'hiddenPrefixTypeNode', 'hiddenSuffixTypeNode', 'mapTypeNode', 'numberTypeNode', 'optionTypeNode', 'postOffsetTypeNode', 'preOffsetTypeNode', 'publicKeyTypeNode', 'remainderOptionTypeNode', 'sentinelTypeNode', 'setTypeNode', 'sizePrefixTypeNode', 'solAmountTypeNode', 'stringTypeNode', 'structFieldTypeNode', 'structTypeNode', 'tupleTypeNode', 'zeroableOptionTypeNode', ] as const; export type TransformableTypeNodeKind = (typeof INPUT_VALUE_TRANSFORMER_SUPPORTED_NODE_KINDS)[number]; export type InputValueTransformerOptions = { bytesEncoding?: BytesEncoding; }; /** * A transformer function that converts user input to Codama codec-compatible format. */ export type InputTransformer = (input: unknown) => unknown; function unexpectedNodeFallback(node: Node): never { throw new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, { expectedKinds: [...INPUT_VALUE_TRANSFORMER_SUPPORTED_NODE_KINDS], kind: node.kind, node, }); } export function createInputValueTransformerVisitor( root: RootNode, options: InputValueTransformerOptions = {}, ): Visitor { const bytesEncoding = options.bytesEncoding ?? 'base16'; const visitor: Visitor = { visitAmountType(node) { return visitOrElse(node.number, visitor, unexpectedNodeFallback); }, visitArrayType(node) { const itemTransform = visitOrElse(node.item, visitor, unexpectedNodeFallback); return (input: unknown) => { if (!Array.isArray(input)) { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__UNEXPECTED_ARGUMENT_TYPE, { actualType: formatValueType(input), expectedType: 'array', nodeKind: 'arrayTypeNode', }); } return input.map(itemTransform); }; }, visitBooleanType() { return (input: unknown) => input; }, visitBytesType() { return (input: unknown) => { if (isUint8Array(input)) { return [bytesEncoding, uint8ArrayToEncodedString(input, bytesEncoding)]; } // Accept number[] by coercing to Uint8Array. if (Array.isArray(input) && input.every(item => typeof item === 'number')) { return [bytesEncoding, uint8ArrayToEncodedString(new Uint8Array(input), bytesEncoding)]; } throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__UNEXPECTED_ARGUMENT_TYPE, { actualType: formatValueType(input), expectedType: 'Uint8Array | number[]', nodeKind: 'bytesTypeNode', }); }; }, visitDateTimeType(node) { return visitOrElse(node.number, visitor, unexpectedNodeFallback); }, visitDefinedTypeLink(node) { const definedType = root.program.definedTypes.find(dt => dt.name === node.name); if (!definedType) { throw new CodamaError(CODAMA_ERROR__LINKED_NODE_NOT_FOUND, { kind: 'definedTypeLinkNode', linkNode: node, name: node.name, path: [], }); } return visitOrElse(definedType.type, visitor, unexpectedNodeFallback); }, visitEnumType(node) { // Scalar enums pass through (just numbers/strings) // Data enums need variant transformation with PascalCase __kind // Because @codama/dynamic-codecs applies pascalCase() to variant names when building discriminated union codecs: // @see https://github.com/codama-idl/codama/blob/main/packages/dynamic-codecs/src/codecs.ts#L199 return (input: unknown) => { if (typeof input === 'number' || typeof input === 'string') { return input; } if (!isObjectRecord(input)) { return input; } if (!('__kind' in input)) { return input; } const { __kind, ...rest } = input; const kindObj = { __kind: pascalCase(String(__kind)) }; const variantNode = node.variants.find(v => v.name === __kind); if (!variantNode) { const availableVariants = node.variants.map(v => v.name).join(', '); throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__UNEXPECTED_ARGUMENT_TYPE, { actualType: `variant '${String(__kind)}'`, expectedType: `one of [${availableVariants}]`, nodeKind: 'enumTypeNode', }); } if (isNode(variantNode, 'enumEmptyVariantTypeNode')) { return { ...input, ...kindObj }; } if (isNode(variantNode, 'enumStructVariantTypeNode')) { const structTransform = visitOrElse(variantNode.struct, visitor, unexpectedNodeFallback); const transformedFields = structTransform(rest); if (!isObjectRecord(transformedFields)) { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__UNEXPECTED_ARGUMENT_TYPE, { actualType: formatValueType(transformedFields), expectedType: 'object', nodeKind: 'enumStructVariantTypeNode', }); } return { ...kindObj, ...transformedFields }; } if (isNode(variantNode, 'enumTupleVariantTypeNode')) { const tupleTransform = visitOrElse(variantNode.tuple, visitor, unexpectedNodeFallback); if (!('fields' in rest) || !Array.isArray(rest.fields)) { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__UNEXPECTED_ARGUMENT_TYPE, { actualType: formatValueType(rest.fields ?? rest), expectedType: 'array (fields)', nodeKind: 'enumTupleVariantTypeNode', }); } return { ...kindObj, fields: tupleTransform(rest.fields) }; } return input; }; }, visitFixedSizeType(node) { return visitOrElse(node.type, visitor, unexpectedNodeFallback); }, visitHiddenPrefixType(node) { return visitOrElse(node.type, visitor, unexpectedNodeFallback); }, visitHiddenSuffixType(node) { return visitOrElse(node.type, visitor, unexpectedNodeFallback); }, visitMapType(node) { // Maps are represented as objects in dynamic-codecs const valueTransform = visitOrElse(node.value, visitor, unexpectedNodeFallback); return (input: unknown) => { if (!isObjectRecord(input)) { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__UNEXPECTED_ARGUMENT_TYPE, { actualType: formatValueType(input), expectedType: 'object', nodeKind: 'mapTypeNode', }); } const result: Record = {}; for (const [key, value] of Object.entries(input)) { result[key] = valueTransform(value); } return result; }; }, // Primitive types (pass through) visitNumberType() { return (input: unknown) => input; }, visitOptionType(node) { const innerTransform = visitOrElse(node.item, visitor, unexpectedNodeFallback); return (input: unknown) => { if (input === null || input === undefined) return input; return innerTransform(input); }; }, visitPostOffsetType(node) { return visitOrElse(node.type, visitor, unexpectedNodeFallback); }, visitPreOffsetType(node) { return visitOrElse(node.type, visitor, unexpectedNodeFallback); }, visitPublicKeyType() { return (input: unknown) => input; }, visitRemainderOptionType(node) { const innerTransform = visitOrElse(node.item, visitor, unexpectedNodeFallback); return (input: unknown) => { if (input === null || input === undefined) return input; return innerTransform(input); }; }, visitSentinelType(node) { return visitOrElse(node.type, visitor, unexpectedNodeFallback); }, visitSetType(node) { // Sets are represented as arrays in dynamic-codecs const itemTransform = visitOrElse(node.item, visitor, unexpectedNodeFallback); return (input: unknown) => { if (!Array.isArray(input)) { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__UNEXPECTED_ARGUMENT_TYPE, { actualType: formatValueType(input), expectedType: 'array', nodeKind: 'setTypeNode', }); } return input.map(itemTransform); }; }, visitSizePrefixType(node) { return visitOrElse(node.type, visitor, unexpectedNodeFallback); }, visitSolAmountType(node) { return visitOrElse(node.number, visitor, unexpectedNodeFallback); }, visitStringType() { return (input: unknown) => input; }, visitStructFieldType(node) { return visitOrElse(node.type, visitor, unexpectedNodeFallback); }, visitStructType(node) { const fieldTransformers = node.fields.map(field => { const transform = visitOrElse(field, visitor, unexpectedNodeFallback); return { name: field.name, transform }; }); return (input: unknown) => { if (!isObjectRecord(input)) { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__UNEXPECTED_ARGUMENT_TYPE, { actualType: formatValueType(input), expectedType: 'object', nodeKind: 'structTypeNode', }); } const result = { ...input } as Record; for (const { name, transform } of fieldTransformers) { if (name in result) { result[name] = transform(result[name]); } } return result; }; }, visitTupleType(node) { const itemTransforms = node.items.map(item => visitOrElse(item, visitor, unexpectedNodeFallback)); return (input: unknown) => { if (!Array.isArray(input)) { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__UNEXPECTED_ARGUMENT_TYPE, { actualType: formatValueType(input), expectedType: 'array', nodeKind: 'tupleTypeNode', }); } if (input.length !== itemTransforms.length) { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__UNEXPECTED_ARGUMENT_TYPE, { actualType: `array(length:${input.length})`, expectedType: `array(length:${itemTransforms.length})`, nodeKind: 'tupleTypeNode', }); } return input.map((value: unknown, index) => itemTransforms[index](value)); }; }, visitZeroableOptionType(node) { const innerTransform = visitOrElse(node.item, visitor, unexpectedNodeFallback); return (input: unknown) => { if (input === null || input === undefined) return input; return innerTransform(input); }; }, }; return visitor; } /** * Creates a transformer function that converts user input to codec-compatible input format. * For example: user input Uint8Array for binary data but @codama/dynamic-codecs expects [BytesEncoding, string] as input * * @param typeNode - The Codama type node describing the expected structure * @param root - Root node for resolving definedTypeLinkNode references * @param options - Configuration options (encoding preference) * @returns Transformer function that converts input to codec format * * @example * const transformer = createInputValueTransformer( * bytesTypeNode(), * root, * { bytesEncoding: 'base16' } * ); * * const input = new Uint8Array([72, 101, 108, 108, 111]); * const transformed = transformer(input); // => ['base16', '48656c6c6f'] * Usage with codec: codamaCodec.encode(['base16', '48656c6c6f']) */ export function createInputValueTransformer( typeNode: TypeNode, root: RootNode, options?: InputValueTransformerOptions, ): InputTransformer { const visitor = createInputValueTransformerVisitor(root, options); return visitOrElse(typeNode, visitor, unexpectedNodeFallback); } ================================================ FILE: packages/dynamic-client/src/instruction-encoding/visitors/pda-seed-value.ts ================================================ import { getNodeCodec } from '@codama/dynamic-codecs'; import { CODAMA_ERROR__DYNAMIC_CLIENT__ARGUMENT_MISSING, CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_DERIVE_PDA, CODAMA_ERROR__DYNAMIC_CLIENT__INVARIANT_VIOLATION, CODAMA_ERROR__DYNAMIC_CLIENT__NODE_REFERENCE_NOT_FOUND, CODAMA_ERROR__UNEXPECTED_NODE_KIND, CodamaError, } from '@codama/errors'; import type { Address } from '@solana/addresses'; import type { ReadonlyUint8Array } from '@solana/codecs'; import type { AccountValueNode, ArgumentValueNode, BooleanValueNode, BytesValueNode, ConstantValueNode, NoneValueNode, NumberValueNode, ProgramIdValueNode, PublicKeyValueNode, SomeValueNode, StringValueNode, TypeNode, Visitor, } from 'codama'; import { isNode, visitOrElse } from 'codama'; import { toAddress } from '../../shared/address'; import { getCodecFromBytesEncoding } from '../../shared/bytes-encoding'; import { getMemoizedAddressEncoder, getMemoizedBooleanEncoder, getMemoizedUtf8Codec } from '../../shared/codecs'; import { resolveAccountValueNodeAddress } from '../resolvers/resolve-account-value-node-address'; import type { BaseResolutionContext } from '../resolvers/types'; import { createInputValueTransformer } from './input-value-transformer'; export const PDA_SEED_VALUE_SUPPORTED_NODE_KINDS = [ 'accountValueNode', 'argumentValueNode', 'booleanValueNode', 'bytesValueNode', 'constantValueNode', 'noneValueNode', 'numberValueNode', 'programIdValueNode', 'publicKeyValueNode', 'someValueNode', 'stringValueNode', ] as const; type PdaSeedValueSupportedNodeKind = (typeof PDA_SEED_VALUE_SUPPORTED_NODE_KINDS)[number]; type PdaSeedValueVisitorContext = BaseResolutionContext & { programId: Address; seedTypeNode?: TypeNode; }; /** * Visitor for resolving PdaSeedValueNode value to raw bytes. * Supports recursive resolution of dependent PDAs (accounts that are themselves auto-derived PDAs). * This is used for both: * - Variable seeds (e.g. seeds based on instruction accounts/arguments), and * - Constant seeds (e.g. bytes/string/programId/publicKey constants). */ export function createPdaSeedValueVisitor( ctx: PdaSeedValueVisitorContext, ): Visitor, PdaSeedValueSupportedNodeKind> { const { root, ixNode, programId, seedTypeNode, resolversInput, resolutionPath } = ctx; const accountsInput = ctx.accountsInput ?? {}; const argumentsInput = ctx.argumentsInput ?? {}; return { visitAccountValue: async (node: AccountValueNode) => { const resolvedAddress = await resolveAccountValueNodeAddress(node, { accountsInput, argumentsInput, ixNode, resolutionPath, resolversInput, root, }); if (resolvedAddress === null) { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_DERIVE_PDA, { accountName: node.name, }); } return getMemoizedAddressEncoder().encode(resolvedAddress); }, visitArgumentValue: async (node: ArgumentValueNode) => { const ixArgumentNode = ixNode.arguments.find(arg => arg.name === node.name); if (!ixArgumentNode) { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__NODE_REFERENCE_NOT_FOUND, { instructionName: ixNode.name, referencedName: node.name, }); } const argInput = argumentsInput[node.name]; // Use the PDA seed's declared type (e.g. plain stringTypeNode) rather than // the instruction argument's type (e.g. sizePrefixTypeNode) so the seed // bytes match what the on-chain program derives. const typeNode = seedTypeNode ?? ixArgumentNode.type; if (argInput === undefined || argInput === null) { // optional remainderOptionTypeNode seeds encodes to zero bytes. if (isNode(typeNode, 'remainderOptionTypeNode')) { return new Uint8Array(0); } throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__ARGUMENT_MISSING, { argumentName: node.name, instructionName: ixNode.name, }); } const codec = getNodeCodec([root, root.program, ixNode, { ...ixArgumentNode, type: typeNode }]); const transformer = createInputValueTransformer(typeNode, root, { bytesEncoding: 'base16', }); const transformedInput = transformer(argInput); return await Promise.resolve(codec.encode(transformedInput)); }, visitBooleanValue: async (node: BooleanValueNode) => await Promise.resolve(getMemoizedBooleanEncoder().encode(node.boolean)), visitBytesValue: async (node: BytesValueNode) => { const encodedValue = getCodecFromBytesEncoding(node.encoding).encode(node.data); return await Promise.resolve(encodedValue); }, visitConstantValue: async (node: ConstantValueNode) => { const innerVisitor = createPdaSeedValueVisitor(ctx); return await visitOrElse(node.value, innerVisitor, innerNode => { throw new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, { expectedKinds: [...PDA_SEED_VALUE_SUPPORTED_NODE_KINDS], kind: innerNode.kind, node: innerNode, }); }); }, visitNoneValue: async (_node: NoneValueNode) => await Promise.resolve(new Uint8Array(0)), visitNumberValue: async (node: NumberValueNode) => { // Sanity check: a violation here indicates a malformed IDL, not a user input error. if (!Number.isInteger(node.number) || node.number < 0 || node.number > 0xff) { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__INVARIANT_VIOLATION, { message: `NumberValueNode PDA seed is out of range: must be a valid u8 (0–255), got ${node.number}`, }); } return await Promise.resolve(new Uint8Array([node.number])); }, visitProgramIdValue: async (_node: ProgramIdValueNode) => { return await Promise.resolve(getMemoizedAddressEncoder().encode(toAddress(programId))); }, visitPublicKeyValue: async (node: PublicKeyValueNode) => { return await Promise.resolve(getMemoizedAddressEncoder().encode(toAddress(node.publicKey))); }, visitSomeValue: async (node: SomeValueNode) => { const innerVisitor = createPdaSeedValueVisitor(ctx); return await visitOrElse(node.value, innerVisitor, innerNode => { throw new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, { expectedKinds: [...PDA_SEED_VALUE_SUPPORTED_NODE_KINDS], kind: innerNode.kind, node: innerNode, }); }); }, visitStringValue: async (node: StringValueNode) => await Promise.resolve(getMemoizedUtf8Codec().encode(node.string)), }; } ================================================ FILE: packages/dynamic-client/src/instruction-encoding/visitors/value-node-value.ts ================================================ import { CODAMA_ERROR__UNEXPECTED_NODE_KIND, CodamaError } from '@codama/errors'; import { address } from '@solana/addresses'; import type { Visitor } from 'codama'; import type { ArrayValueNode, BooleanValueNode, BytesValueNode, ConstantValueNode, EnumValueNode, MapValueNode, NoneValueNode, NumberValueNode, PublicKeyValueNode, SetValueNode, SomeValueNode, StringValueNode, StructValueNode, TupleValueNode, } from 'codama'; import { visitOrElse } from 'codama'; type ResolvedValue = { encoding?: string; kind: string; value: unknown; }; export const VALUE_NODE_SUPPORTED_NODE_KINDS = [ 'arrayValueNode', 'booleanValueNode', 'bytesValueNode', 'constantValueNode', 'enumValueNode', 'mapValueNode', 'noneValueNode', 'numberValueNode', 'publicKeyValueNode', 'setValueNode', 'someValueNode', 'stringValueNode', 'structValueNode', 'tupleValueNode', ] as const; type ValueNodeSupportedNodeKind = (typeof VALUE_NODE_SUPPORTED_NODE_KINDS)[number]; /** * Visitor for resolving regular ValueNode types to their typed values. */ export function createValueNodeVisitor(): Visitor { const visitor: Visitor = { visitArrayValue: (node: ArrayValueNode) => ({ kind: node.kind, value: node.items.map(item => visitOrElse(item, visitor, n => { throw new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, { expectedKinds: [...VALUE_NODE_SUPPORTED_NODE_KINDS], kind: n.kind, node: n, }); }), ), }), visitBooleanValue: (node: BooleanValueNode) => ({ kind: node.kind, value: node.boolean, }), visitBytesValue: (node: BytesValueNode) => ({ encoding: node.encoding, kind: node.kind, value: node.data, }), visitConstantValue: (node: ConstantValueNode) => { return visitOrElse(node.value, visitor, innerNode => { throw new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, { expectedKinds: [...VALUE_NODE_SUPPORTED_NODE_KINDS], kind: innerNode.kind, node: innerNode, }); }); }, visitEnumValue: (node: EnumValueNode) => ({ kind: node.kind, value: node.variant, }), visitMapValue: (node: MapValueNode) => ({ kind: node.kind, value: node.entries.map(entry => ({ key: visitOrElse(entry.key, visitor, n => { throw new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, { expectedKinds: [...VALUE_NODE_SUPPORTED_NODE_KINDS], kind: n.kind, node: n, }); }), value: visitOrElse(entry.value, visitor, n => { throw new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, { expectedKinds: [...VALUE_NODE_SUPPORTED_NODE_KINDS], kind: n.kind, node: n, }); }), })), }), visitNoneValue: (node: NoneValueNode) => ({ kind: node.kind, value: null, }), visitNumberValue: (node: NumberValueNode) => ({ kind: node.kind, value: node.number, }), visitPublicKeyValue: (node: PublicKeyValueNode) => ({ kind: node.kind, value: address(node.publicKey), }), visitSetValue: (node: SetValueNode) => ({ kind: node.kind, value: node.items.map(item => visitOrElse(item, visitor, n => { throw new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, { expectedKinds: [...VALUE_NODE_SUPPORTED_NODE_KINDS], kind: n.kind, node: n, }); }), ), }), visitSomeValue: (node: SomeValueNode) => { return visitOrElse(node.value, visitor, innerNode => { throw new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, { expectedKinds: [...VALUE_NODE_SUPPORTED_NODE_KINDS], kind: innerNode.kind, node: innerNode, }); }); }, visitStringValue: (node: StringValueNode) => ({ kind: node.kind, value: node.string, }), visitStructValue: (node: StructValueNode) => ({ kind: node.kind, value: Object.fromEntries( node.fields.map(field => [ field.name, visitOrElse(field.value, visitor, n => { throw new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, { expectedKinds: [...VALUE_NODE_SUPPORTED_NODE_KINDS], kind: n.kind, node: n, }); }), ]), ), }), visitTupleValue: (node: TupleValueNode) => ({ kind: node.kind, value: node.items.map(item => visitOrElse(item, visitor, n => { throw new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, { expectedKinds: [...VALUE_NODE_SUPPORTED_NODE_KINDS], kind: n.kind, node: n, }); }), ), }), }; return visitor; } ================================================ FILE: packages/dynamic-client/src/program-client/collect-pdas.ts ================================================ import { isNode, type PdaNode, type RootNode } from 'codama'; /** * Collects unique PDA definitions from the IDL. * * Scans both `root.program.pdas` (registered PDAs) and inline * `pdaValueNode > pdaNode` definitions inside instruction account * `defaultValue` nodes. Deduplicates by PDA name. */ export function collectPdaNodes(root: RootNode): Map { const pdas = new Map(); for (const pda of root.program.pdas) { pdas.set(pda.name, pda); } for (const ix of root.program.instructions) { for (const acc of ix.accounts) { if (!acc.defaultValue || !isNode(acc.defaultValue, 'pdaValueNode')) continue; if (!isNode(acc.defaultValue.pda, 'pdaNode')) continue; const pdaNode = acc.defaultValue.pda; if (!pdas.has(pdaNode.name)) { pdas.set(pdaNode.name, pdaNode); } } } return pdas; } ================================================ FILE: packages/dynamic-client/src/program-client/create-program-client.ts ================================================ import { CODAMA_ERROR__DYNAMIC_CLIENT__INSTRUCTION_NOT_FOUND, CODAMA_ERROR__DYNAMIC_CLIENT__PDA_NOT_FOUND, CodamaError, } from '@codama/errors'; import { type Address, address, type ProgramDerivedAddress } from '@solana/addresses'; import type { Instruction } from '@solana/instructions'; import type { InstructionNode, RootNode } from 'codama'; import { createFromJson, updateProgramsVisitor } from 'codama'; import type { AddressInput } from '../shared/address'; import { toAddress } from '../shared/address'; import type { AccountsInput, ArgumentsInput, ResolversInput } from '../shared/types'; import { collectPdaNodes } from './collect-pdas'; import { deriveStandalonePDA } from './derive-standalone-pda'; import { MethodsBuilder } from './methods-builder'; export type IdlInput = object | string; export type CreateProgramClientOptions = { /** * Optional override for the program id. * If not provided, uses `root.program.publicKey` from the IDL. */ programId?: AddressInput; }; export type ProgramClient = { /** Quick lookup by instruction name. */ instructions: Map; /** Anchor-like facade namespace for building instructions. */ methods: Record ProgramMethodBuilder>; /** Anchor-like facade namespace for standalone PDA derivation. */ pdas?: Record) => Promise>; /** Program id as an `Address`. */ programAddress: Address; /** Parsed Codama root node for advanced use-cases. */ root: RootNode; }; export type ProgramMethodBuilder = { accounts(accounts: AccountsInput): ProgramMethodBuilder; instruction(): Promise; resolvers(resolvers: ResolversInput): ProgramMethodBuilder; signers(signers: string[]): ProgramMethodBuilder; }; /** * Creates a program client from a Codama IDL. * * For type safety, generate types and pass as a generic. See the README.md for details. */ export function createProgramClient( idl: IdlInput, options: CreateProgramClientOptions = {}, ): TClient { const json = typeof idl === 'string' ? idl : JSON.stringify(idl); const codama = createFromJson(json); if (options.programId) { codama.update( updateProgramsVisitor({ [codama.getRoot().program.name]: { publicKey: toAddress(options.programId), }, }), ); } const root = codama.getRoot(); const programAddress = address(root.program.publicKey); const instructions = new Map(); for (const ix of root.program.instructions) { instructions.set(ix.name, ix); } const methods = new Proxy( {}, { get(_target, prop) { if (typeof prop !== 'string' || PASSTHROUGH_PROPS.has(prop)) return undefined; const ixNode = instructions.get(prop); if (!ixNode) { if (prop in Object.prototype) return undefined; throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__INSTRUCTION_NOT_FOUND, { availableIxs: [...instructions.keys()], instructionName: prop, }); } return (args?: ArgumentsInput) => new MethodsBuilder(root, ixNode, args) as ProgramMethodBuilder; }, has(target, prop) { return Reflect.has(target, prop) || (typeof prop === 'string' && instructions.has(prop)); }, }, ) as ProgramClient['methods']; const pdaNodes = collectPdaNodes(root); const pdas = pdaNodes.size === 0 ? undefined : (new Proxy( {}, { get(_target, prop) { if (typeof prop !== 'string' || PASSTHROUGH_PROPS.has(prop)) return undefined; const pdaNode = pdaNodes.get(prop); if (!pdaNode) { if (prop in Object.prototype) return undefined; const available = [...pdaNodes.keys()].join(', '); throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__PDA_NOT_FOUND, { available, pdaName: prop, }); } return (seeds?: Record) => deriveStandalonePDA(root, pdaNode, seeds); }, has(target, prop) { return Reflect.has(target, prop) || (typeof prop === 'string' && pdaNodes.has(prop)); }, }, ) as ProgramClient['pdas']); return { instructions, methods, pdas, programAddress, root, } as unknown as TClient; } const PASSTHROUGH_PROPS = new Set(['then', 'toJSON', 'valueOf', 'toString']); ================================================ FILE: packages/dynamic-client/src/program-client/derive-standalone-pda.ts ================================================ import { getNodeCodec } from '@codama/dynamic-codecs'; import { CODAMA_ERROR__DYNAMIC_CLIENT__ARGUMENT_MISSING, CODAMA_ERROR__DYNAMIC_CLIENT__UNEXPECTED_ARGUMENT_TYPE, CODAMA_ERROR__UNEXPECTED_NODE_KIND, CODAMA_ERROR__UNRECOGNIZED_NODE_KIND, CodamaError, } from '@codama/errors'; import type { Address, ProgramDerivedAddress } from '@solana/addresses'; import { getProgramDerivedAddress } from '@solana/addresses'; import type { ReadonlyUint8Array } from '@solana/codecs'; import type { InstructionNode, PdaNode, RegisteredPdaSeedNode, RootNode, VariablePdaSeedNode } from 'codama'; import { camelCase, isNode, visitOrElse } from 'codama'; import { createInputValueTransformer, createPdaSeedValueVisitor, PDA_SEED_VALUE_SUPPORTED_NODE_KINDS, } from '../instruction-encoding'; import { toAddress } from '../shared/address'; import { getMemoizedUtf8Encoder } from '../shared/codecs'; import { formatValueType, getMaybeNodeKind } from '../shared/util'; /** * Minimal InstructionNode stub to satisfy constant PDA seeds requirements. * Constant seeds only use programIdValue / publicKeyValue / bytesValue / stringValue, none of which reference instruction arguments or accounts */ const STANDALONE_IX_NODE: InstructionNode = { accounts: [], arguments: [], kind: 'instructionNode', name: '__standalone__' as InstructionNode['name'], }; /** * Derives a PDA from a standalone `PdaNode` and user-supplied seed values, * without requiring an instruction context. */ export async function deriveStandalonePDA( root: RootNode, pdaNode: PdaNode, seedInputs: Record = {}, ): Promise { const programAddress = toAddress(pdaNode.programId || root.program.publicKey); const seedValues = await Promise.all( pdaNode.seeds.map(async (seedNode): Promise => { if (seedNode.kind === 'constantPdaSeedNode') { return await resolveStandaloneConstantSeed(root, programAddress, seedNode); } if (seedNode.kind === 'variablePdaSeedNode') { return await resolveStandaloneVariableSeed(root, seedNode, seedInputs); } throw new CodamaError(CODAMA_ERROR__UNRECOGNIZED_NODE_KIND, { kind: getMaybeNodeKind(seedNode) ?? 'unknown', }); }), ); return await getProgramDerivedAddress({ programAddress, seeds: seedValues }); } function resolveStandaloneConstantSeed( root: RootNode, programAddress: Address, seedNode: RegisteredPdaSeedNode, ): Promise { if (!isNode(seedNode, 'constantPdaSeedNode')) { throw new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, { expectedKinds: ['constantPdaSeedNode'], kind: seedNode.kind, node: seedNode, }); } const visitor = createPdaSeedValueVisitor({ accountsInput: undefined, argumentsInput: undefined, ixNode: STANDALONE_IX_NODE, programId: programAddress, resolutionPath: [], resolversInput: undefined, root, }); return visitOrElse(seedNode.value, visitor, node => { throw new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, { expectedKinds: Array.from(PDA_SEED_VALUE_SUPPORTED_NODE_KINDS), kind: node.kind, node, }); }); } function resolveStandaloneVariableSeed( root: RootNode, seedNode: VariablePdaSeedNode, seedInputs: Record, ): Promise { const input = seedInputs[seedNode.name]; const typeNode = seedNode.type; // remainderOptionTypeNode seeds are optional — null means zero bytes. if (input === undefined || input === null) { if (isNode(typeNode, 'remainderOptionTypeNode')) { return Promise.resolve(new Uint8Array(0)); } throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__ARGUMENT_MISSING, { argumentName: seedNode.name, instructionName: camelCase('standaloneSeedNode'), }); } // For simple string seeds encode directly with UTF-8 (no length prefix) if (isNode(typeNode, 'stringTypeNode')) { if (typeof input !== 'string') { throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__UNEXPECTED_ARGUMENT_TYPE, { actualType: formatValueType(input), expectedType: 'string', nodeKind: 'stringTypeNode', }); } return Promise.resolve(getMemoizedUtf8Encoder().encode(input)); } // Create a synthetic instructionArgumentNode so getNodeCodec can resolve the type. // The seed's declared type is used directly (no size-prefix wrapper). const syntheticArgNode = createSyntheticArgNode(seedNode); const codec = getNodeCodec([root, root.program, syntheticArgNode]); const transformer = createInputValueTransformer(typeNode, root, { bytesEncoding: 'base16' }); const transformedInput = transformer(input); return Promise.resolve(codec.encode(transformedInput)); } function createSyntheticArgNode(seedNode: VariablePdaSeedNode) { return { docs: [] as string[], kind: 'instructionArgumentNode' as const, name: seedNode.name, type: seedNode.type, }; } ================================================ FILE: packages/dynamic-client/src/program-client/methods-builder.ts ================================================ import type { Instruction } from '@solana/instructions'; import type { InstructionNode, RootNode } from 'codama'; import { createIxBuilder } from '../instruction-encoding/instructions'; import type { AccountsInput, ArgumentsInput, EitherSigners, ResolversInput } from '../shared/types'; export class MethodsBuilder { private _accounts?: AccountsInput; // "either" signers Account names private _signers?: EitherSigners; // Custom resolver functions for ResolverValueNode private _resolvers?: ResolversInput; constructor( private readonly root: RootNode, private readonly ixNode: InstructionNode, private readonly args?: ArgumentsInput, ) {} accounts(accounts: AccountsInput) { this._accounts = accounts; return this; } // Explicitly provide Account names which must be Signers. // This is to help InstructionAccountNode resolution with ambiguous isSigner: "either". Other signers will be auto-resolved signers(signers: EitherSigners) { this._signers = signers; return this; } resolvers(resolvers: ResolversInput) { this._resolvers = resolvers; return this; } async instruction(): Promise { const build = createIxBuilder(this.root, this.ixNode); return await build(this.args, this._accounts, this._signers, this._resolvers); } } ================================================ FILE: packages/dynamic-client/src/shared/address.ts ================================================ import { CODAMA_ERROR__DYNAMIC_CLIENT__CANNOT_CONVERT_TO_ADDRESS, CodamaError } from '@codama/errors'; import type { Address } from '@solana/addresses'; import { address, isAddress } from '@solana/addresses'; import { safeStringify } from './util'; /** * Accept both modern Address strings and legacy PublicKey-like objects. * We intentionally use duck-typing to avoid hard dependency on @solana/web3.js types. */ export type PublicKeyLike = { toBase58(): string }; export type AddressInput = Address | PublicKeyLike | string; export function isPublicKeyLike(value: unknown): value is PublicKeyLike { const obj = value as Record; return typeof value === 'object' && value !== null && 'toBase58' in obj && typeof obj.toBase58 === 'function'; } export function toAddress(input: AddressInput): Address { if (isPublicKeyLike(input)) return address(input.toBase58()); if (typeof input === 'string' && isAddress(input)) return address(input); throw new CodamaError(CODAMA_ERROR__DYNAMIC_CLIENT__CANNOT_CONVERT_TO_ADDRESS, { value: safeStringify(input), }); } export function isConvertibleAddress(value: unknown): value is AddressInput { if (value == null) return false; return isPublicKeyLike(value) || (typeof value === 'string' && isAddress(value)); } ================================================ FILE: packages/dynamic-client/src/shared/bytes-encoding.ts ================================================ import { CODAMA_ERROR__UNRECOGNIZED_BYTES_ENCODING, CodamaError } from '@codama/errors'; import type { BytesEncoding } from 'codama'; import { getMemoizedBase16Codec, getMemoizedBase58Codec, getMemoizedBase64Codec, getMemoizedUtf8Codec } from './codecs'; import { safeStringify } from './util'; /** * Converts Uint8Array to encoded string based on encoding type. * Uses @solana/codecs encoders internally for consistent encoding/decoding. */ export function uint8ArrayToEncodedString(bytes: Uint8Array, encoding: BytesEncoding): string { const codec = getCodecFromBytesEncoding(encoding); return codec.decode(bytes); } /** * Gets the appropriate codec for a given bytes encoding format. */ export function getCodecFromBytesEncoding(encoding: BytesEncoding) { switch (encoding) { case 'base16': return getMemoizedBase16Codec(); case 'base58': return getMemoizedBase58Codec(); case 'base64': return getMemoizedBase64Codec(); case 'utf8': return getMemoizedUtf8Codec(); default: throw new CodamaError(CODAMA_ERROR__UNRECOGNIZED_BYTES_ENCODING, { encoding: safeStringify(encoding as unknown), }); } } /** * Type guard to check if a value is a Uint8Array. */ export function isUint8Array(value: unknown): value is Uint8Array { return value instanceof Uint8Array; } ================================================ FILE: packages/dynamic-client/src/shared/codecs.ts ================================================ import { getAddressEncoder } from '@solana/addresses'; import type { Encoder } from '@solana/codecs'; import { getBase16Codec, getBase58Codec, getBase64Codec, getBooleanEncoder, getUtf8Codec, getUtf8Encoder, } from '@solana/codecs'; // Memoized encoders and codecs to avoid unnecessary re-instantiation. let addressEncoder: ReturnType | undefined; export function getMemoizedAddressEncoder() { if (!addressEncoder) addressEncoder = getAddressEncoder(); return addressEncoder; } let utf8Encoder: ReturnType | undefined; export function getMemoizedUtf8Encoder() { if (!utf8Encoder) utf8Encoder = getUtf8Encoder(); return utf8Encoder; } let booleanEncoder: Encoder | undefined; export function getMemoizedBooleanEncoder() { if (!booleanEncoder) booleanEncoder = getBooleanEncoder(); return booleanEncoder; } let utf8Codec: ReturnType | undefined; export function getMemoizedUtf8Codec() { if (!utf8Codec) utf8Codec = getUtf8Codec(); return utf8Codec; } let base16Codec: ReturnType | undefined; export function getMemoizedBase16Codec() { if (!base16Codec) base16Codec = getBase16Codec(); return base16Codec; } let base58Codec: ReturnType | undefined; export function getMemoizedBase58Codec() { if (!base58Codec) base58Codec = getBase58Codec(); return base58Codec; } let base64Codec: ReturnType | undefined; export function getMemoizedBase64Codec() { if (!base64Codec) base64Codec = getBase64Codec(); return base64Codec; } ================================================ FILE: packages/dynamic-client/src/shared/nodes.ts ================================================ export const OPTIONAL_NODE_KINDS = ['optionTypeNode', 'zeroableOptionTypeNode', 'remainderOptionTypeNode']; ================================================ FILE: packages/dynamic-client/src/shared/types.ts ================================================ import type { Instruction } from '@solana/instructions'; import type { AddressInput } from './address'; // Note: optional accounts may be explicitly set to null. export type AccountsInput = Partial>; export type ArgumentsInput = Partial>; type AccountName = string; export type EitherSigners = AccountName[]; export type ResolverFn = (argumentsInput: ArgumentsInput, accountsInput: AccountsInput) => Promise; export type ResolversInput = Record; type TBuildIxFn = ( argumentsInput?: ArgumentsInput, accountsInput?: AccountsInput, signers?: EitherSigners, resolversInput?: ResolversInput, ) => Promise; export type BuildIxFn = TBuildIxFn; ================================================ FILE: packages/dynamic-client/src/shared/util.ts ================================================ import type { NodeKind } from 'codama'; /** * Checks if a value is a plain object record (struct-like). */ export function isObjectRecord(value: unknown): value is Record { return typeof value === 'object' && value !== null && Object.getPrototypeOf(value) === Object.prototype; } /** Returns the `NodeKind` of a node or `null`. */ export function getMaybeNodeKind(node: unknown): NodeKind | null { if (!isObjectRecord(node)) return null; return (node as { kind: NodeKind }).kind ?? null; } export function formatValueType(value: unknown): string { if (value === null) return 'null'; if (Array.isArray(value)) return `array (length ${value.length})`; if (value instanceof Uint8Array) return `Uint8Array (length ${value.length})`; if (typeof value === 'object') return 'object'; return typeof value; } /** * Serializes a value for use in error messages and diagnostic output. * Converts BigInt to strings, always returns a string and never throws. */ export function safeStringify(value: unknown): string { try { return JSON.stringify(value, (_key, v: unknown) => (typeof v === 'bigint' ? String(v) : v)); } catch { return `non-serializable ${formatValueType(value)}`; } } ================================================ FILE: packages/dynamic-client/src/types/index.ts ================================================ export type { AddressInput, PublicKeyLike } from '../shared/address'; export type { AccountsInput, ArgumentsInput } from '../shared/types'; export type { CreateProgramClientOptions, IdlInput, ProgramClient, ProgramMethodBuilder, } from '../program-client/create-program-client'; ================================================ FILE: packages/dynamic-client/test/programs/anchor/Anchor.toml ================================================ [toolchain] [features] resolution = true skip-lint = false [programs.localnet] anchor-codama = "5xjPsgMHuoj4MrAPJVBrTomk5UAZvCxVtAdcWwgheoZs" blog = "1rAs9KgDjEnMVrU1nJPWVhN4b6W4VEBxzcNJoeJpbVR" [registry] url = "https://api.apr.dev" [provider] cluster = "Localnet" wallet = "~/.config/solana/id.json" [scripts] test = "pnpm ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.spec.ts" ================================================ FILE: packages/dynamic-client/test/programs/anchor/Cargo.toml ================================================ [workspace] members = ["programs/*"] resolver = "2" [profile.release] overflow-checks = true lto = "fat" codegen-units = 1 [profile.release.build-override] opt-level = 3 incremental = false codegen-units = 1 ================================================ FILE: packages/dynamic-client/test/programs/anchor/programs/blog/Cargo.toml ================================================ [package] name = "blog" version = "0.1.0" description = "Created with Anchor" edition = "2021" [lib] crate-type = ["cdylib", "lib"] name = "blog" [features] default = [] cpi = ["no-entrypoint"] no-entrypoint = [] no-idl = [] no-log-ix-name = [] idl-build = ["anchor-lang/idl-build"] [dependencies] anchor-lang = "=0.32.1" ================================================ FILE: packages/dynamic-client/test/programs/anchor/programs/blog/Xargo.toml ================================================ [target.bpfel-unknown-unknown.dependencies.std] features = [] ================================================ FILE: packages/dynamic-client/test/programs/anchor/programs/blog/src/lib.rs ================================================ #![allow(unexpected_cfgs)] use anchor_lang::prelude::*; declare_id!("1rAs9KgDjEnMVrU1nJPWVhN4b6W4VEBxzcNJoeJpbVR"); #[program] pub mod blog { use super::*; pub fn create_profile(ctx: Context, username: String) -> Result<()> { let profile = &mut ctx.accounts.profile; profile.authority = ctx.accounts.authority.key(); profile.username = username; profile.post_count = 0; profile.bump = ctx.bumps.profile; Ok(()) } pub fn create_post( ctx: Context, title: String, content: String, ) -> Result<()> { let profile = &mut ctx.accounts.profile; let post = &mut ctx.accounts.post; post.author = profile.key(); post.id = profile.post_count; post.title = title; post.content = content; post.bump = ctx.bumps.post; profile.post_count += 1; Ok(()) } pub fn update_post( ctx: Context, _post_id: u64, title: String, content: String, ) -> Result<()> { let post = &mut ctx.accounts.post; post.title = title; post.content = content; Ok(()) } pub fn create_category(ctx: Context, name: String) -> Result<()> { let category = &mut ctx.accounts.category; category.creator = ctx.accounts.creator.key(); category.name = name; category.bump = ctx.bumps.category; Ok(()) } pub fn subscribe(ctx: Context) -> Result<()> { let subscription = &mut ctx.accounts.subscription; subscription.follower = ctx.accounts.follower.key(); subscription.author = ctx.accounts.author.key(); subscription.bump = ctx.bumps.subscription; Ok(()) } pub fn react(ctx: Context, kind: u8) -> Result<()> { let reaction = &mut ctx.accounts.reaction; reaction.post = ctx.accounts.post.key(); reaction.user = ctx.accounts.user.key(); reaction.kind = kind; reaction.bump = ctx.bumps.reaction; Ok(()) } pub fn create_daily_digest( ctx: Context, year: u16, month: u8, day: u8, ) -> Result<()> { let digest = &mut ctx.accounts.daily_digest; digest.profile = ctx.accounts.profile.key(); digest.year = year; digest.month = month; digest.day = day; digest.post_count = 0; digest.bump = ctx.bumps.daily_digest; Ok(()) } pub fn create_access_grant( ctx: Context, permissions: [u8; 4], ) -> Result<()> { let grant = &mut ctx.accounts.access_grant; grant.profile = ctx.accounts.profile.key(); grant.permissions = permissions; grant.bump = ctx.bumps.access_grant; Ok(()) } pub fn create_bookmark_list( ctx: Context, bookmarks: Vec, ) -> Result<()> { let list = &mut ctx.accounts.bookmark_list; list.owner = ctx.accounts.owner.key(); list.bookmarks = bookmarks; list.bump = ctx.bumps.bookmark_list; Ok(()) } } #[derive(Accounts)] #[instruction(username: String)] pub struct CreateProfile<'info> { #[account(mut)] pub authority: Signer<'info>, #[account( init, payer = authority, space = 8 + Profile::INIT_SPACE, seeds = [b"profile", authority.key().as_ref()], bump )] pub profile: Account<'info, Profile>, pub system_program: Program<'info, System>, } #[derive(Accounts)] #[instruction(title: String, content: String)] pub struct CreatePost<'info> { #[account(mut)] pub authority: Signer<'info>, #[account( mut, seeds = [b"profile", authority.key().as_ref()], bump = profile.bump, has_one = authority, )] pub profile: Account<'info, Profile>, #[account( init, payer = authority, space = 8 + Post::INIT_SPACE, seeds = [b"post", profile.key().as_ref(), &profile.post_count.to_le_bytes()], bump )] pub post: Account<'info, Post>, pub system_program: Program<'info, System>, } #[derive(Accounts)] #[instruction(post_id: u64)] pub struct UpdatePost<'info> { pub authority: Signer<'info>, #[account( seeds = [b"profile", authority.key().as_ref()], bump = profile.bump, has_one = authority, )] pub profile: Account<'info, Profile>, #[account( mut, seeds = [b"post", profile.key().as_ref(), &post_id.to_le_bytes()], bump = post.bump, has_one = author, )] pub post: Account<'info, Post>, /// CHECK: validated via has_one on post pub author: UncheckedAccount<'info>, } #[derive(Accounts)] #[instruction(name: String)] pub struct CreateCategory<'info> { #[account(mut)] pub creator: Signer<'info>, #[account( init, payer = creator, space = 8 + Category::INIT_SPACE, seeds = [b"category", name.as_bytes()], bump )] pub category: Account<'info, Category>, pub system_program: Program<'info, System>, } #[derive(Accounts)] pub struct Subscribe<'info> { #[account(mut)] pub follower: Signer<'info>, /// CHECK: the author profile being followed pub author: UncheckedAccount<'info>, #[account( init, payer = follower, space = 8 + Subscription::INIT_SPACE, seeds = [b"sub", follower.key().as_ref(), author.key().as_ref()], bump )] pub subscription: Account<'info, Subscription>, pub system_program: Program<'info, System>, } #[derive(Accounts)] #[instruction(kind: u8)] pub struct React<'info> { #[account(mut)] pub user: Signer<'info>, /// CHECK: the post being reacted to pub post: UncheckedAccount<'info>, #[account( init, payer = user, space = 8 + Reaction::INIT_SPACE, seeds = [b"reaction", post.key().as_ref(), user.key().as_ref(), &kind.to_le_bytes()], bump )] pub reaction: Account<'info, Reaction>, pub system_program: Program<'info, System>, } #[derive(Accounts)] #[instruction(year: u16, month: u8, day: u8)] pub struct CreateDailyDigest<'info> { #[account(mut)] pub authority: Signer<'info>, #[account( seeds = [b"profile", authority.key().as_ref()], bump = profile.bump, has_one = authority, )] pub profile: Account<'info, Profile>, #[account( init, payer = authority, space = 8 + DailyDigest::INIT_SPACE, seeds = [b"digest", profile.key().as_ref(), &year.to_le_bytes(), &month.to_le_bytes(), &day.to_le_bytes()], bump )] pub daily_digest: Account<'info, DailyDigest>, pub system_program: Program<'info, System>, } #[account] #[derive(InitSpace)] pub struct Profile { pub authority: Pubkey, #[max_len(32)] pub username: String, pub post_count: u64, pub bump: u8, } #[account] #[derive(InitSpace)] pub struct Post { pub author: Pubkey, pub id: u64, #[max_len(64)] pub title: String, #[max_len(512)] pub content: String, pub bump: u8, } #[account] #[derive(InitSpace)] pub struct Category { pub creator: Pubkey, #[max_len(32)] pub name: String, pub bump: u8, } #[account] #[derive(InitSpace)] pub struct Subscription { pub follower: Pubkey, pub author: Pubkey, pub bump: u8, } #[account] #[derive(InitSpace)] pub struct Reaction { pub post: Pubkey, pub user: Pubkey, pub kind: u8, pub bump: u8, } #[derive(Accounts)] #[instruction(permissions: [u8; 4])] pub struct CreateAccessGrant<'info> { #[account(mut)] pub authority: Signer<'info>, #[account( seeds = [b"profile", authority.key().as_ref()], bump = profile.bump, has_one = authority, )] pub profile: Account<'info, Profile>, #[account( init, payer = authority, space = 8 + AccessGrant::INIT_SPACE, seeds = [b"grant", profile.key().as_ref(), permissions.as_ref()], bump )] pub access_grant: Account<'info, AccessGrant>, pub system_program: Program<'info, System>, } #[derive(Accounts)] #[instruction(bookmarks: Vec)] pub struct CreateBookmarkList<'info> { #[account(mut)] pub owner: Signer<'info>, #[account( init, payer = owner, space = 8 + BookmarkList::INIT_SPACE, seeds = [b"bookmarks", owner.key().as_ref()], bump )] pub bookmark_list: Account<'info, BookmarkList>, pub system_program: Program<'info, System>, } #[account] #[derive(InitSpace)] pub struct DailyDigest { pub profile: Pubkey, pub year: u16, pub month: u8, pub day: u8, pub post_count: u8, pub bump: u8, } #[account] #[derive(InitSpace)] pub struct AccessGrant { pub profile: Pubkey, pub permissions: [u8; 4], pub bump: u8, } #[account] #[derive(InitSpace)] pub struct BookmarkList { pub owner: Pubkey, #[max_len(10)] pub bookmarks: Vec, pub bump: u8, } ================================================ FILE: packages/dynamic-client/test/programs/anchor/programs/example/Cargo.toml ================================================ [package] name = "example" version = "0.1.0" description = "Created with Anchor" edition = "2021" [lib] crate-type = ["cdylib", "lib"] name = "example" [features] default = [] cpi = ["no-entrypoint"] no-entrypoint = [] no-idl = [] no-log-ix-name = [] idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"] [dependencies] anchor-lang = "=0.32.1" anchor-spl = "=0.32.1" ================================================ FILE: packages/dynamic-client/test/programs/anchor/programs/example/Xargo.toml ================================================ [target.bpfel-unknown-unknown.dependencies.std] features = [] ================================================ FILE: packages/dynamic-client/test/programs/anchor/programs/example/src/lib.rs ================================================ #![allow(unexpected_cfgs)] use anchor_lang::prelude::*; use anchor_spl::{token::{Token, Mint, TokenAccount}, associated_token::AssociatedToken}; mod nested_example; pub use nested_example::*; declare_id!("5xjPsgMHuoj4MrAPJVBrTomk5UAZvCxVtAdcWwgheoZs"); #[program] pub mod example { use super::*; pub fn pubkey_seed_ix(ctx: Context, input: u64) -> Result<()> { ctx.accounts.new_account.input = input; ctx.accounts.new_account.bump = ctx.bumps.new_account; Ok(()) } pub fn update_optional_input( ctx: Context, input: u64, optional_input: Option, ) -> Result<()> { ctx.accounts.existing_account.input = input; ctx.accounts.existing_account.optional_input = optional_input; Ok(()) } pub fn update_optional_account(ctx: Context, _id: u64) -> Result<()> { ctx.accounts.created_optional_acc.optional_acc = ctx.accounts.optional_acc_key.as_ref().map(|acc| acc.key()); Ok(()) } pub fn no_arguments(_ctx: Context) -> Result<()> { Ok(()) } pub fn external_programs_with_pda(_ctx: Context) -> Result<()> { Ok(()) } pub fn four_level_pda(_ctx: Context) -> Result<()> { Ok(()) } pub fn self_reference_pda(_ctx: Context) -> Result<()> { Ok(()) } pub fn two_node_cycle_pda(_ctx: Context) -> Result<()> { Ok(()) } pub fn nested_example(ctx: Context, input: StructAndEnumsInput) -> Result<()> { nested_example::handler(ctx, input) } pub fn string_seed_pda(ctx: Context, _name: String, id: u64) -> Result<()> { ctx.accounts.pda_account.input = id; ctx.accounts.pda_account.bump = ctx.bumps.pda_account; Ok(()) } } #[derive(Accounts)] pub struct PubkeySeedIx<'info> { #[account(mut)] pub signer: Signer<'info>, #[account( init, payer = signer, space = 8 + 8 + 1 + 32 + 1, seeds = [b"seed", signer.key().as_ref()], bump )] pub new_account: Account<'info, DataAccount1>, pub system_program: Program<'info, System>, } #[account] #[derive(InitSpace)] pub struct DataAccount1 { input: u64, optional_input: Option, bump: u8, } #[derive(Accounts)] pub struct UpdateOptionalInput<'info> { pub signer: Signer<'info>, #[account( mut, seeds = [b"seed", signer.key().as_ref()], bump = existing_account.bump )] pub existing_account: Account<'info, DataAccount1>, } #[derive(Accounts)] #[instruction(id: u64)] pub struct UpdateOptionalAccount<'info> { #[account(mut)] pub signer: Signer<'info>, #[account( init, seeds = [b"optional_acc".as_ref(), &id.to_le_bytes()], payer = signer, space = 8 + StoreOptionalAccount::INIT_SPACE, bump, )] pub created_optional_acc: Account<'info, StoreOptionalAccount>, pub optional_acc_key: Option>, pub system_program: Program<'info, System>, } #[derive(Accounts)] pub struct NoArguments<'info> { #[account(mut)] pub signer: Signer<'info>, #[account( init, payer = signer, space = 8 + StoreOptionalAccount::INIT_SPACE, )] pub acc: Account<'info, StoreOptionalAccount>, pub system_program: Program<'info, System>, } #[account] #[derive(InitSpace)] pub struct StoreOptionalAccount { optional_acc: Option, } #[derive(Accounts)] pub struct ExternalProgramsWithPdaIx<'info> { #[account(mut)] pub signer: Signer<'info>, // mint and token_account are to check auto-resolution with external program #[account( init, payer = signer, mint::decimals = 9, mint::authority = signer, )] pub mint: Account<'info, Mint>, #[account( init, payer = signer, associated_token::mint = mint, associated_token::authority = signer, )] pub token_account: Account<'info, TokenAccount>, // dependent_account to check that auto-resolution and seeds derivation from both: // signer (accountInput) and token_account (another auto-derived account) #[account( init, payer = signer, space = 8 + DataAccount1::INIT_SPACE, seeds = [b"signer_and_ata", signer.key().as_ref(), token_account.key().as_ref()], bump )] pub dependent_account: Account<'info, DataAccount1>, pub system_program: Program<'info, System>, pub token_program: Program<'info, Token>, pub associated_token_program: Program<'info, AssociatedToken>, pub rent: Sysvar<'info, Rent>, } #[derive(Accounts)] pub struct FourLevelPda<'info> { #[account(mut)] pub signer: Signer<'info>, #[account( init, payer = signer, space = 8 + DataAccount1::INIT_SPACE, seeds = [b"level1", signer.key().as_ref()], bump )] pub level1: Account<'info, DataAccount1>, #[account( init, payer = signer, space = 8 + DataAccount1::INIT_SPACE, seeds = [b"level2", level1.key().as_ref()], bump )] pub level2: Account<'info, DataAccount1>, #[account( init, payer = signer, space = 8 + DataAccount1::INIT_SPACE, seeds = [b"level3", level2.key().as_ref()], bump )] pub level3: Account<'info, DataAccount1>, #[account( init, payer = signer, space = 8 + DataAccount1::INIT_SPACE, seeds = [b"level4", level3.key().as_ref()], bump )] pub level4: Account<'info, DataAccount1>, pub system_program: Program<'info, System>, } #[derive(Accounts)] pub struct SelfReferencePda<'info> { #[account(mut)] pub signer: Signer<'info>, #[account( init, payer = signer, space = 8 + DataAccount1::INIT_SPACE, seeds = [b"recursive", recursive.key().as_ref()], bump )] pub recursive: Account<'info, DataAccount1>, pub system_program: Program<'info, System>, } #[derive(Accounts)] pub struct TwoNodeCyclePda<'info> { #[account(mut)] pub signer: Signer<'info>, #[account( init, payer = signer, space = 8 + DataAccount1::INIT_SPACE, seeds = [b"pda_a", pda_b.key().as_ref()], bump )] pub pda_a: Account<'info, DataAccount1>, #[account( init, payer = signer, space = 8 + DataAccount1::INIT_SPACE, seeds = [b"pda_b", pda_a.key().as_ref()], bump )] pub pda_b: Account<'info, DataAccount1>, pub system_program: Program<'info, System>, } // Reproducer for the PDA seed type mismatch: // The `name` argument is a Rust `String`, which Borsh serializes with a u32 length prefix // (sizePrefixTypeNode in Codama). But the PDA seed uses `name.as_bytes()` — raw UTF-8 bytes // without any prefix (stringTypeNode in Codama). Without the proper seedTypeNode in // pda-seed-value.ts, the library would encode the seed with the length prefix, deriving // the wrong PDA address. #[derive(Accounts)] #[instruction(name: String, id: u64)] pub struct StringSeedPda<'info> { #[account(mut)] pub signer: Signer<'info>, #[account( init, payer = signer, space = 8 + DataAccount1::INIT_SPACE, seeds = [&id.to_le_bytes(), name.as_bytes()], bump )] pub pda_account: Account<'info, DataAccount1>, pub system_program: Program<'info, System>, } ================================================ FILE: packages/dynamic-client/test/programs/anchor/programs/example/src/nested_example.rs ================================================ use anchor_lang::prelude::*; use anchor_lang::Space; // All arguments are stored in the NestedExampleAccount.input field for testing. #[derive(AnchorSerialize, AnchorDeserialize, Clone)] pub struct StructAndEnumsInput { pub header: InnerHeader, pub inner_struct: InnerStruct, pub inner_enum: InnerEnum, pub seed_enum: SeedEnum, pub pubkey: Pubkey, } #[account] #[derive(InitSpace)] pub struct NestedExampleAccount { pub input: StructAndEnumsInput, } // We need to implement Space for all structures for size calculation. impl Space for StructAndEnumsInput { const INIT_SPACE: usize = InnerHeader::INIT_SPACE + InnerStruct::INIT_SPACE + InnerEnum::INIT_SPACE + SeedEnum::INIT_SPACE + 32; // Pubkey field } // header: InnerHeader #[derive(AnchorSerialize, AnchorDeserialize, Clone)] pub struct InnerHeader { pub version: u32, pub command: Command, } impl Space for InnerHeader { const INIT_SPACE: usize = 4 + Command::INIT_SPACE; } // command: Command #[derive(AnchorSerialize, AnchorDeserialize, Clone)] pub enum Command { Start(u64), Stop, Continue { reason: String }, } impl Space for Command { const INIT_SPACE: usize = 1 + 8 + 4 + 64; // discriminant + u64 + String (max 64 for simplicity) } // inner_struct: InnerStruct #[derive(AnchorSerialize, AnchorDeserialize, Clone)] pub struct InnerStruct { pub value: u64, pub name: String, pub seed_enum: SeedEnum, pub bytes: Vec, pub optional_pubkey: Option, pub enums_array: [SeedEnum; 2], } impl Space for InnerStruct { const INIT_SPACE: usize = 8 // value: u64 + 4 + 32 // name: String (max 32 for simplicity) + SeedEnum::INIT_SPACE + 4 + 32 // bytes: Vec (max 32 for simplicity) + 1 + 32 // optional_pubkey: Option + 2 * SeedEnum::INIT_SPACE; // enums_array } // inner_enum: InnerEnum #[derive(AnchorSerialize, AnchorDeserialize, Clone)] pub enum InnerEnum { TokenTransfer { amount: u64, token_type: TokenType }, Stake { duration: u64 }, None, } impl Space for InnerEnum { const INIT_SPACE: usize = 1 + 8 + TokenType::INIT_SPACE; } #[derive(AnchorSerialize, AnchorDeserialize, Clone)] pub enum TokenType { SPL, NFT { collection: String }, } impl Space for TokenType { const INIT_SPACE: usize = 1 + 4 + 64; } // seed_enum: SeedEnum (used as example of nested enum PDA seed) #[derive(AnchorSerialize, AnchorDeserialize, Clone)] pub enum SeedEnum { Arm = 0, Bar = 1, Car = 2, } impl SeedEnum { pub fn as_seed(&self) -> [u8; 1] { [self.clone() as u8] } } impl Space for SeedEnum { const INIT_SPACE: usize = 1; } #[derive(Accounts)] #[instruction(input: StructAndEnumsInput)] pub struct NestedStructsAndEnums<'info> { #[account(mut)] pub signer: Signer<'info>, // The PDA account is derived using multiple fields from the input arguments, demonstrating complex seed derivation. // Dependency from argument doesn't produce pdaAccountNode with seeds in Codama IDL. #[account( init, payer = signer, space = 8 + NestedExampleAccount::INIT_SPACE, seeds = [ b"nested_example_account", input.pubkey.as_ref(), input.seed_enum.as_seed().as_ref(), input.inner_struct.seed_enum.as_seed().as_ref(), ], bump )] pub nested_example_account: Account<'info, NestedExampleAccount>, pub system_program: Program<'info, System>, } pub fn handler( ctx: Context, input: StructAndEnumsInput, ) -> Result<()> { let nested_example_account = &mut ctx.accounts.nested_example_account; nested_example_account.input = input; Ok(()) } ================================================ FILE: packages/dynamic-client/test/programs/anchor/rust-toolchain.toml ================================================ [toolchain] channel = "1.93.0" ================================================ FILE: packages/dynamic-client/test/programs/anchor/tests/blog.test.ts ================================================ import path from 'node:path'; import { getNodeCodec } from '@codama/dynamic-codecs'; import { type Address, getProgramDerivedAddress } from '@solana/addresses'; import { beforeEach, describe, expect, test } from 'vitest'; import { createProgramClient } from '../../../../src'; import type { BlogProgramClient } from '../../generated/blog-idl-types'; import { loadIdl, SvmTestContext } from '../../test-utils'; const idl = loadIdl('blog-idl.json'); const programClient = createProgramClient(idl); const programSoPath = path.resolve(__dirname, '..', '..', 'dumps', 'blog.so'); describe('blog', () => { let ctx: SvmTestContext; let payer: Address; beforeEach(async () => { ctx = new SvmTestContext({ defaultPrograms: true }); ctx.loadProgram(programClient.programAddress, programSoPath); payer = await ctx.createFundedAccount(); }); describe('category PDA — string seed', () => { test('should create a category and read it back via pdas helper', async () => { const ix = await programClient.methods .createCategory({ name: 'solana' }) .accounts({ creator: payer }) .instruction(); await ctx.sendInstruction(ix, [payer]); const [categoryPda] = await programClient.pdas.category({ name: 'solana' }); const decoded = decodeAccount('category', categoryPda); expect(decoded.creator).toBe(payer); expect(decoded.name).toBe('solana'); }); test('should derive distinct PDAs for different category names', async () => { for (const name of ['tech', 'art', 'science']) { const ix = await programClient.methods .createCategory({ name }) .accounts({ creator: payer }) .instruction(); await ctx.sendInstruction(ix, [payer]); } const [techPda] = await programClient.pdas.category({ name: 'tech' }); const [artPda] = await programClient.pdas.category({ name: 'art' }); const [sciencePda] = await programClient.pdas.category({ name: 'science' }); expect(decodeAccount('category', techPda).name).toBe('tech'); expect(decodeAccount('category', artPda).name).toBe('art'); expect(decodeAccount('category', sciencePda).name).toBe('science'); }); }); describe('subscription PDA — two pubkey seeds', () => { test('should create a subscription and read it back via pdas helper', async () => { const author = payer; const follower = await ctx.createFundedAccount(); const ix = await programClient.methods.subscribe().accounts({ author, follower }).instruction(); await ctx.sendInstruction(ix, [follower]); const [subPda] = await programClient.pdas.subscription({ author, follower }); const decoded = decodeAccount('subscription', subPda); expect(decoded.follower).toBe(follower); expect(decoded.author).toBe(author); }); test('should derive distinct PDAs when follower/author are swapped', async () => { const alice = await ctx.createFundedAccount(); const bob = await ctx.createFundedAccount(); // Alice follows Bob const ix1 = await programClient.methods .subscribe() .accounts({ author: bob, follower: alice }) .instruction(); await ctx.sendInstruction(ix1, [alice]); // Bob follows Alice const ix2 = await programClient.methods .subscribe() .accounts({ author: alice, follower: bob }) .instruction(); await ctx.sendInstruction(ix2, [bob]); const [sub1] = await programClient.pdas.subscription({ author: bob, follower: alice }); const [sub2] = await programClient.pdas.subscription({ author: alice, follower: bob }); expect(decodeAccount('subscription', sub1).follower).toBe(alice); expect(decodeAccount('subscription', sub2).follower).toBe(bob); }); }); describe('post PDA — updatePost auto-derives post from postId argument', () => { test('should create a post then update it with auto-derived PDA', async () => { // Create profile const createProfileIx = await programClient.methods .createProfile({ username: 'writer' }) .accounts({ authority: payer }) .instruction(); await ctx.sendInstruction(createProfileIx, [payer]); const [profilePda] = await programClient.pdas.profile({ authority: payer }); // Create post (manual PDA — Codama can't express profile.post_count dependency) const [postPda] = await programClient.pdas.post({ postId: 0, profile: profilePda }); const createPostIx = await programClient.methods .createPost({ content: 'Original content', title: 'Original' }) .accounts({ authority: payer, post: postPda }) .instruction(); await ctx.sendInstruction(createPostIx, [payer]); // Update post — post account should auto-derive from postId arg + profile account const updatePostIx = await programClient.methods .updatePost({ content: 'Updated content', postId: 0, title: 'Updated' }) .accounts({ author: profilePda, authority: payer }) .instruction(); await ctx.sendInstruction(updatePostIx, [payer]); const decoded = decodeAccount('post', postPda); expect(decoded.title).toBe('Updated'); expect(decoded.content).toBe('Updated content'); }); }); describe('reaction PDA — two pubkeys + u8 seed', () => { test('should create a reaction and read it back via pdas helper', async () => { // Setup: create profile + post const createProfileIx = await programClient.methods .createProfile({ username: 'alice' }) .accounts({ authority: payer }) .instruction(); await ctx.sendInstruction(createProfileIx, [payer]); const [profilePda] = await programClient.pdas.profile({ authority: payer }); const [postPda] = await programClient.pdas.post({ postId: 0, profile: profilePda }); const createPostIx = await programClient.methods .createPost({ content: 'World', title: 'Hello' }) .accounts({ authority: payer, post: postPda }) .instruction(); await ctx.sendInstruction(createPostIx, [payer]); // React with kind=1 (like) const reactor = await ctx.createFundedAccount(); const ix = await programClient.methods .react({ kind: 1 }) .accounts({ post: postPda, user: reactor }) .instruction(); await ctx.sendInstruction(ix, [reactor]); const [reactionPda] = await programClient.pdas.reaction({ kind: 1, post: postPda, user: reactor, }); const decoded = decodeAccount('reaction', reactionPda); expect(decoded.post).toBe(postPda); expect(decoded.user).toBe(reactor); expect(decoded.kind).toBe(1); }); test('should derive distinct PDAs for different reaction kinds on the same post', async () => { // Setup: create profile + post const createProfileIx = await programClient.methods .createProfile({ username: 'bob' }) .accounts({ authority: payer }) .instruction(); await ctx.sendInstruction(createProfileIx, [payer]); const [profilePda] = await programClient.pdas.profile({ authority: payer }); const [postPda] = await programClient.pdas.post({ postId: 0, profile: profilePda }); const createPostIx = await programClient.methods .createPost({ content: 'There', title: 'Hi' }) .accounts({ authority: payer, post: postPda }) .instruction(); await ctx.sendInstruction(createPostIx, [payer]); // Same user, two reaction kinds const reactor = await ctx.createFundedAccount(); for (const kind of [0, 1]) { const ix = await programClient.methods .react({ kind }) .accounts({ post: postPda, user: reactor }) .instruction(); await ctx.sendInstruction(ix, [reactor]); } const [likePda] = await programClient.pdas.reaction({ kind: 0, post: postPda, user: reactor }); const [lovePda] = await programClient.pdas.reaction({ kind: 1, post: postPda, user: reactor }); expect(decodeAccount('reaction', likePda).kind).toBe(0); expect(decodeAccount('reaction', lovePda).kind).toBe(1); }); }); describe('dailyDigest PDA — pubkey + u16 + u8 + u8 seeds', () => { test('should create a daily digest and read it back via pdas helper', async () => { const createProfileIx = await programClient.methods .createProfile({ username: 'charlie' }) .accounts({ authority: payer }) .instruction(); await ctx.sendInstruction(createProfileIx, [payer]); const [profilePda] = await programClient.pdas.profile({ authority: payer }); const ix = await programClient.methods .createDailyDigest({ day: 25, month: 2, year: 2026 }) .accounts({ authority: payer }) .instruction(); await ctx.sendInstruction(ix, [payer]); const [digestPda] = await programClient.pdas.dailyDigest({ day: 25, month: 2, profile: profilePda, year: 2026, }); const decoded = decodeAccount('dailyDigest', digestPda); expect(decoded.profile).toBe(profilePda); expect(decoded.year).toBe(2026); expect(decoded.month).toBe(2); expect(decoded.day).toBe(25); expect(decoded.postCount).toBe(0); }); test('should derive distinct PDAs for different dates', async () => { const createProfileIx = await programClient.methods .createProfile({ username: 'dave' }) .accounts({ authority: payer }) .instruction(); await ctx.sendInstruction(createProfileIx, [payer]); const [profilePda] = await programClient.pdas.profile({ authority: payer }); const dates = [ { day: 1, month: 1, year: 2026 }, { day: 2, month: 1, year: 2026 }, { day: 1, month: 2, year: 2026 }, ]; for (const date of dates) { const ix = await programClient.methods .createDailyDigest(date) .accounts({ authority: payer }) .instruction(); await ctx.sendInstruction(ix, [payer]); } for (const date of dates) { const [pda] = await programClient.pdas.dailyDigest({ profile: profilePda, ...date }); const decoded = decodeAccount('dailyDigest', pda); expect(decoded.year).toBe(date.year); expect(decoded.month).toBe(date.month); expect(decoded.day).toBe(date.day); } }); }); describe('accessGrant PDA — pubkey + [u8; 4] array seed', () => { test('should create an access grant and read it back via pdas helper', async () => { const createProfileIx = await programClient.methods .createProfile({ username: 'eve' }) .accounts({ authority: payer }) .instruction(); await ctx.sendInstruction(createProfileIx, [payer]); const [profilePda] = await programClient.pdas.profile({ authority: payer }); const permissions = new Uint8Array([1, 0, 1, 0]); // read, no-write, execute, no-admin const ix = await programClient.methods .createAccessGrant({ permissions }) .accounts({ authority: payer }) .instruction(); await ctx.sendInstruction(ix, [payer]); const [grantPda] = await programClient.pdas.accessGrant({ permissions, profile: profilePda, }); const decoded = decodeAccount('accessGrant', grantPda); expect(decoded.profile).toBe(profilePda); expect(decodeBytes(decoded.permissions)).toEqual([1, 0, 1, 0]); }); test('should derive distinct PDAs for different permission sets', async () => { const createProfileIx = await programClient.methods .createProfile({ username: 'frank' }) .accounts({ authority: payer }) .instruction(); await ctx.sendInstruction(createProfileIx, [payer]); const [profilePda] = await programClient.pdas.profile({ authority: payer }); const readOnly = new Uint8Array([1, 0, 0, 0]); const fullAccess = new Uint8Array([1, 1, 1, 1]); for (const permissions of [readOnly, fullAccess]) { const ix = await programClient.methods .createAccessGrant({ permissions }) .accounts({ authority: payer }) .instruction(); await ctx.sendInstruction(ix, [payer]); } const [readPda] = await programClient.pdas.accessGrant({ permissions: readOnly, profile: profilePda }); const [fullPda] = await programClient.pdas.accessGrant({ permissions: fullAccess, profile: profilePda }); expect(decodeBytes(decodeAccount('accessGrant', readPda).permissions)).toEqual([1, 0, 0, 0]); expect(decodeBytes(decodeAccount('accessGrant', fullPda).permissions)).toEqual([1, 1, 1, 1]); }); }); describe('bookmarkList PDA — pubkey seed with Vec arg', () => { test('should create a bookmark list with vec arg and read it back via pdas helper', async () => { const bookmark1 = await ctx.createAccount(); const bookmark2 = await ctx.createAccount(); const bookmark3 = await ctx.createAccount(); const ix = await programClient.methods .createBookmarkList({ bookmarks: [bookmark1, bookmark2, bookmark3] }) .accounts({ owner: payer }) .instruction(); await ctx.sendInstruction(ix, [payer]); const [listPda] = await programClient.pdas.bookmarkList({ owner: payer }); const decoded = decodeAccount('bookmarkList', listPda); expect(decoded.owner).toBe(payer); expect(decoded.bookmarks).toEqual([bookmark1, bookmark2, bookmark3]); }); test('should create a bookmark list with empty vec', async () => { const ix = await programClient.methods .createBookmarkList({ bookmarks: [] }) .accounts({ owner: payer }) .instruction(); await ctx.sendInstruction(ix, [payer]); const [listPda] = await programClient.pdas.bookmarkList({ owner: payer }); const decoded = decodeAccount('bookmarkList', listPda); expect(decoded.owner).toBe(payer); expect(decoded.bookmarks).toEqual([]); }); }); describe('category PDA — matches manual derivation with root program', () => { test('should derive PDA using root program address when no pdaNode.programId', async () => { const [categoryPda] = await programClient.pdas.category({ name: 'my-category' }); const [expectedPda] = await getProgramDerivedAddress({ programAddress: programClient.programAddress, seeds: ['category', 'my-category'], }); expect(categoryPda).toBe(expectedPda); }); }); function decodeAccount(name: string, pda: Address) { const accountNode = programClient.root.program.accounts.find(a => a.name === name); if (!accountNode) throw new Error(`Account node "${name}" not found in IDL`); const codec = getNodeCodec([programClient.root, programClient.root.program, accountNode]); const data = ctx.requireEncodedAccount(pda).data; return codec.decode(Uint8Array.from(data)) as Record; } /** Codama decodes fixedSize(bytes) as ['base64', encoded] — convert back to number[] */ function decodeBytes(value: unknown): number[] { if (Array.isArray(value) && value[0] === 'base64' && typeof value[1] === 'string') { return [...Buffer.from(value[1], 'base64')]; } throw new Error(`Expected ['base64', string], got: ${JSON.stringify(value)}`); } }); ================================================ FILE: packages/dynamic-client/test/programs/anchor/tests/example.test.ts ================================================ import { getNodeCodec } from '@codama/dynamic-codecs'; import { type Address, getAddressEncoder, getProgramDerivedAddress } from '@solana/addresses'; import { getU64Encoder, type Option, unwrapOption } from '@solana/codecs'; import type { RootNode } from 'codama'; import { beforeEach, describe, expect, test } from 'vitest'; import { createProgramClient } from '../../../../src'; import type { ExampleProgramClient } from '../../generated/example-idl-types'; import { SvmTestContext } from '../../test-utils'; import { createTestContext, idl, programClient } from './helpers'; describe('anchor-example: commonIxs', () => { let ctx: SvmTestContext; let payer: Address; beforeEach(async () => { ({ ctx, payer } = await createTestContext()); }); describe('pubkeySeedIx', () => { test('should execute instruction with pubkey seed', async () => { const ix = await programClient.methods .pubkeySeedIx({ input: 42 }) .accounts({ signer: payer }) .instruction(); await ctx.sendInstruction(ix, [payer]); }); }); describe('updateOptionalInput', () => { test('should update optional input field with and without value', async () => { const signer = await ctx.createFundedAccount(); const ix0 = await programClient.methods.pubkeySeedIx({ input: 42 }).accounts({ signer }).instruction(); await ctx.sendInstruction(ix0, [signer]); const [pda] = await getProgramDerivedAddress({ programAddress: programClient.programAddress, seeds: ['seed', getAddressEncoder().encode(signer)], }); const optionalAddress = await ctx.createAccount(); const ix1 = await programClient.methods .updateOptionalInput({ input: 44, optionalInput: optionalAddress, }) .accounts({ signer }) .instruction(); await ctx.sendInstruction(ix1, [signer]); const account1 = ctx.requireEncodedAccount(pda); const decoded1 = decodeDataAccount1(programClient.root, account1.data); expect(decoded1.optionalInput).eq(optionalAddress); const ix2 = await programClient.methods .updateOptionalInput({ input: 45 }) .accounts({ signer }) .instruction(); await ctx.sendInstruction(ix2, [signer]); const account2 = ctx.requireEncodedAccount(pda); const decoded2 = decodeDataAccount1(programClient.root, account2.data); expect(decoded2.optionalInput).toBeNull(); }); }); describe('updateOptionalAccount', () => { test('should handle optional accounts', async () => { const optionalAccount = await ctx.createAccount(); const ix1 = await programClient.methods .updateOptionalAccount({ id: 1 }) .accounts({ optionalAccKey: optionalAccount, signer: payer, }) .instruction(); await ctx.sendInstruction(ix1, [payer]); const ix2 = await programClient.methods .updateOptionalAccount({ id: 2 }) .accounts({ optionalAccKey: null, signer: payer, }) .instruction(); await ctx.sendInstruction(ix2, [payer]); }); }); describe('noArguments', () => { test('should execute instruction with no arguments', async () => { const account = await ctx.createAccount(); const ix = await programClient.methods .noArguments() .accounts({ acc: account, signer: payer, }) .instruction(); await ctx.sendInstruction(ix, [payer, account]); }); }); test('ExternalProgramsWithPdaIx: should resolve dependent pda and external program addresses', async () => { const mint = await ctx.createAccount(); const addressEncoder = getAddressEncoder(); const [expectedAta] = await getProgramDerivedAddress({ programAddress: ctx.ASSOCIATED_TOKEN_PROGRAM_ADDRESS, seeds: [ addressEncoder.encode(payer), addressEncoder.encode(ctx.TOKEN_PROGRAM_ADDRESS), addressEncoder.encode(mint), ], }); const [expectedDependentPda] = await getProgramDerivedAddress({ programAddress: programClient.programAddress, seeds: ['signer_and_ata', addressEncoder.encode(payer), addressEncoder.encode(expectedAta)], }); const ix = await programClient.methods .externalProgramsWithPda() .accounts({ mint, signer: payer, }) .instruction(); expect(ix.accounts).toBeDefined(); if (!ix.accounts) throw new Error('Expected instruction accounts to be defined'); expect(ix.accounts.length).eq(8); const expectedAccounts = [ [payer, "signer doesn't match"], [mint, "mint doesn't match"], [expectedAta, "token_account doesn't match"], [expectedDependentPda, "dependent_account doesn't match"], [ctx.SYSTEM_PROGRAM_ADDRESS, "system_program doesn't match"], [ctx.TOKEN_PROGRAM_ADDRESS, "token_program doesn't match"], [ctx.ASSOCIATED_TOKEN_PROGRAM_ADDRESS, "associated_token_program doesn't match"], [ctx.SYSVAR_RENT_ADDRESS, "rent_sysvar doesn't match"], ]; expectedAccounts.forEach((expected, i) => { if (!ix?.accounts?.[i]) { throw new Error(`Expected instruction accounts to be defined at index ${i}`); } expect(ix.accounts[i].address, expected[1]).eq(expected[0]); }); // Send transaction to verify it executes on-chain await ctx.sendInstruction(ix, [payer, mint]); }); test('FourLevelPdaIx: should resolve four-level dependent PDA', async () => { const ix = await programClient.methods .fourLevelPda() .accounts({ signer: payer, }) .instruction(); expect(ix.accounts).toBeDefined(); if (!ix.accounts) throw new Error('Expected instruction accounts to be defined'); expect(ix.accounts.length).eq(6); const addressEncoder = getAddressEncoder(); const [expectedLevel1] = await getProgramDerivedAddress({ programAddress: programClient.programAddress, seeds: ['level1', addressEncoder.encode(payer)], }); const [expectedLevel2] = await getProgramDerivedAddress({ programAddress: programClient.programAddress, seeds: ['level2', addressEncoder.encode(expectedLevel1)], }); const [expectedLevel3] = await getProgramDerivedAddress({ programAddress: programClient.programAddress, seeds: ['level3', addressEncoder.encode(expectedLevel2)], }); const [expectedLevel4] = await getProgramDerivedAddress({ programAddress: programClient.programAddress, seeds: ['level4', addressEncoder.encode(expectedLevel3)], }); const expectedAccounts = [ [payer, "signer doesn't match"], [expectedLevel1, "level1 doesn't match"], [expectedLevel2, "level2 doesn't match"], [expectedLevel3, "level3 doesn't match"], [expectedLevel4, "level4 doesn't match"], [ctx.SYSTEM_PROGRAM_ADDRESS, "system_program doesn't match"], ]; expectedAccounts.forEach((expected, i) => { if (!ix?.accounts?.[i]) { throw new Error(`Expected instruction accounts to be defined at index ${i}`); } expect(ix.accounts[i].address, expected[1]).eq(expected[0]); }); await ctx.sendInstruction(ix, [payer]); }); describe('stringSeedPda', () => { test('should derive PDA using raw string seed bytes (not size-prefixed)', async () => { const name = 'hello'; const id = 7; const ix = await programClient.methods .stringSeedPda({ id, name }) .accounts({ signer: payer }) .instruction(); await ctx.sendInstruction(ix, [payer]); const [expectedPda] = await getProgramDerivedAddress({ programAddress: programClient.programAddress, seeds: [getU64Encoder().encode(id), name], }); const account = ctx.requireEncodedAccount(expectedPda); expect(account.owner).toBe(programClient.programAddress); const decoded = decodeDataAccount1(programClient.root, account.data); expect(decoded.input).toBe(7n); }); }); describe('Circular Dependency Detection', () => { test('SelfReferencePdaIx: should throw AccountError for A->A cycle', async () => { await expect( programClient.methods.selfReferencePda().accounts({ signer: payer }).instruction(), ).rejects.toThrow(/Circular dependency detected: \[recursive -> recursive\]/); }); test('TwoNodeCyclePdaIx: should throw AccountError for A->B->A pattern in two-node cycle', async () => { await expect( programClient.methods.twoNodeCyclePda().accounts({ signer: payer }).instruction(), ).rejects.toThrow(/Circular dependency detected: \[pda[AB] -> pda[AB] -> pda[AB]\]/); }); }); describe('Standalone PDA derivation — pdaNode.programId', () => { const addressEncoder = getAddressEncoder(); test('should derive cross-program PDA using pdaNode.programId, not root program', async () => { const signer = await SvmTestContext.generateAddress(); const mint = await SvmTestContext.generateAddress(); const [actualPda] = await programClient.pdas.tokenAccount({ mint, signer }); const [expectedPda] = await getProgramDerivedAddress({ programAddress: ctx.ASSOCIATED_TOKEN_PROGRAM_ADDRESS, seeds: [ addressEncoder.encode(signer), addressEncoder.encode(ctx.TOKEN_PROGRAM_ADDRESS), addressEncoder.encode(mint), ], }); expect(actualPda).toBe(expectedPda); }); test('should not be affected by programId option override and still use pdaNode.programId', async () => { const signer = await SvmTestContext.generateAddress(); const mint = await SvmTestContext.generateAddress(); const overrideProgramId = await SvmTestContext.generateAddress(); const overrideClient = createProgramClient(idl, { programId: overrideProgramId }); // double-check that the override took effect expect(overrideClient.programAddress).toBe(overrideProgramId); const [pdaFromOriginal] = await programClient.pdas.tokenAccount({ mint, signer }); const [pdaFromOverride] = await overrideClient.pdas.tokenAccount({ mint, signer }); expect(pdaFromOverride).toBe(pdaFromOriginal); }); test('should fall back to root program when pdaNode has no programId', async () => { const signer = await SvmTestContext.generateAddress(); const [actualPda] = await programClient.pdas.level1({ signer }); const [expectedPda] = await getProgramDerivedAddress({ programAddress: programClient.programAddress, seeds: ['level1', addressEncoder.encode(signer)], }); expect(actualPda).toBe(expectedPda); }); }); }); function decodeDataAccount1( root: RootNode, data: Uint8Array, ): { bump: number; input: bigint; optionalInput: string | null } { const accountNode = root.program.accounts.find(a => a.name === 'dataAccount1'); if (!accountNode) { throw new Error('Could not find account node "dataAccount1" in IDL'); } const codec = getNodeCodec([root, root.program, accountNode]); const decoded = codec.decode(Uint8Array.from(data)) as { bump: number; input: bigint; optionalInput: Option; }; return { bump: decoded.bump, input: decoded.input, optionalInput: unwrapOption(decoded.optionalInput), }; } ================================================ FILE: packages/dynamic-client/test/programs/anchor/tests/helpers.ts ================================================ import path from 'node:path'; import { createProgramClient } from '../../../../src'; import type { ExampleProgramClient } from '../../generated/example-idl-types'; import { loadIdl, SvmTestContext } from '../../test-utils'; export const idl = loadIdl('example-idl.json'); export const programClient = createProgramClient(idl); export const programSoPath = path.resolve(__dirname, '..', 'target', 'deploy', 'example.so'); export async function createTestContext() { const ctx = new SvmTestContext({ defaultPrograms: true }); ctx.loadProgram(programClient.programAddress, programSoPath); const payer = await ctx.createFundedAccount(); return { ctx, payer }; } /** * Encodes and returns a value in base16 codama dynamic-codecs format. * To match bytes decoded by getNodeCodec. */ export function bytesToBase16CodecFormat(bytes: Uint8Array) { return ['base16', Buffer.from(bytes).toString('hex')] as const; } ================================================ FILE: packages/dynamic-client/test/programs/anchor/tests/nested-example-ix.test.ts ================================================ import { getNodeCodec } from '@codama/dynamic-codecs'; import { type Address, getAddressEncoder, getProgramDerivedAddress } from '@solana/addresses'; import { none, some } from '@solana/codecs'; import type { RootNode } from 'codama'; import { beforeEach, describe, expect, test } from 'vitest'; import type { NestedExampleArgs } from '../../generated/example-idl-types'; import { SvmTestContext } from '../../test-utils'; import { bytesToBase16CodecFormat, createTestContext, programClient } from './helpers'; describe('anchor-example: nestedExampleIx', () => { let ctx: SvmTestContext; let payer: Address; beforeEach(async () => { ({ ctx, payer } = await createTestContext()); }); test('should encode nested struct with scalar enums, bytes, fixed array, and none inner enum', async () => { const pubkeyArg = await ctx.createAccount(); const nestedExampleAccount = await deriveNestedExamplePda( programClient.programAddress, pubkeyArg, 'arm', 'bar', ); const ix = await programClient.methods .nestedExample({ input: { header: { command: { __kind: 'start', fields: [42n] }, version: 1 }, innerEnum: { __kind: 'none' }, innerStruct: { bytes: new Uint8Array([1, 2, 3]), enumsArray: ['arm', 'car'], name: 'hello', optionalPubkey: null, seedEnum: 'bar', value: BigInt(100), }, pubkey: pubkeyArg, seedEnum: 'arm', }, }) .accounts({ nestedExampleAccount, signer: payer }) .instruction(); await ctx.sendInstruction(ix, [payer]); expect(ix.data?.length).toBeGreaterThan(0); const exampleAccountData = ctx.requireEncodedAccount(nestedExampleAccount).data; const exampleAccount = decodeNestedExampleAccount(programClient.root, exampleAccountData); expect(exampleAccount.input).toEqual({ header: { command: { __kind: 'Start', fields: [42n] }, version: 1 }, innerEnum: { __kind: 'None' }, innerStruct: { bytes: bytesToBase16CodecFormat(new Uint8Array([1, 2, 3])), enumsArray: [seedEnumToNumber('arm'), seedEnumToNumber('car')], name: 'hello', optionalPubkey: none(), seedEnum: seedEnumToNumber('bar'), value: 100n, }, pubkey: pubkeyArg, seedEnum: seedEnumToNumber('arm'), }); }); test('should encode Command::Continue with reason string [enumStructVariantTypeNode]', async () => { const pubkeyArg = await ctx.createAccount(); const nestedExampleAccount = await deriveNestedExamplePda( programClient.programAddress, pubkeyArg, 'bar', 'arm', ); const ix = await programClient.methods .nestedExample({ input: { header: { command: { __kind: 'continue', reason: 'keep going' }, version: 2 }, innerEnum: { __kind: 'none' }, innerStruct: { bytes: new Uint8Array([]), enumsArray: ['bar', 'bar'], name: 'test', optionalPubkey: null, seedEnum: 'arm', value: BigInt(0), }, pubkey: pubkeyArg, seedEnum: 'bar', }, }) .accounts({ nestedExampleAccount, signer: payer }) .instruction(); await ctx.sendInstruction(ix, [payer]); expect(ix.data?.length).toBeGreaterThan(0); const exampleAccountData = ctx.requireEncodedAccount(nestedExampleAccount).data; const exampleAccount = decodeNestedExampleAccount(programClient.root, exampleAccountData); expect(exampleAccount.input).toEqual({ header: { command: { __kind: 'Continue', reason: 'keep going', }, version: 2, }, innerEnum: { __kind: 'None' }, innerStruct: { bytes: bytesToBase16CodecFormat(new Uint8Array([])), enumsArray: [seedEnumToNumber('bar'), seedEnumToNumber('bar')], name: 'test', optionalPubkey: none(), seedEnum: seedEnumToNumber('arm'), value: 0n, }, pubkey: pubkeyArg, seedEnum: seedEnumToNumber('bar'), }); }); test('should encode InnerEnum::TokenTransfer [enumStructVariantTypeNode->enumEmptyVariantTypeNode]', async () => { const pubkeyArg = await ctx.createAccount(); const nestedExampleAccount = await deriveNestedExamplePda( programClient.programAddress, pubkeyArg, 'car', 'car', ); const ix = await programClient.methods .nestedExample({ input: { header: { command: { __kind: 'stop' }, version: 1 }, innerEnum: { __kind: 'tokenTransfer', amount: BigInt(500), tokenType: { __kind: 'sPL' } }, innerStruct: { bytes: new Uint8Array([0xde, 0xad, 0xbe, 0xef]), enumsArray: ['car', 'arm'], name: 'transfer', optionalPubkey: null, seedEnum: 'car', value: BigInt(999), }, pubkey: pubkeyArg, seedEnum: 'car', }, }) .accounts({ nestedExampleAccount, signer: payer }) .instruction(); await ctx.sendInstruction(ix, [payer]); expect(ix.data?.length).toBeGreaterThan(0); const exampleAccountData = ctx.requireEncodedAccount(nestedExampleAccount).data; const exampleAccount = decodeNestedExampleAccount(programClient.root, exampleAccountData); expect(exampleAccount.input).toEqual({ header: { command: { __kind: 'Stop', }, version: 1, }, innerEnum: { __kind: 'TokenTransfer', amount: 500n, tokenType: { __kind: 'SPL' }, }, innerStruct: { bytes: bytesToBase16CodecFormat(new Uint8Array([0xde, 0xad, 0xbe, 0xef])), enumsArray: [seedEnumToNumber('car'), seedEnumToNumber('arm')], name: 'transfer', optionalPubkey: none(), seedEnum: seedEnumToNumber('car'), value: 999n, }, pubkey: pubkeyArg, seedEnum: seedEnumToNumber('car'), }); }); test('should encode InnerEnum::TokenTransfer enum (3 levels deep)', async () => { const pubkeyArg = await ctx.createAccount(); const nestedExampleAccount = await deriveNestedExamplePda( programClient.programAddress, pubkeyArg, 'arm', 'arm', ); const ix = await programClient.methods .nestedExample({ input: { header: { command: { __kind: 'start', fields: [42n] }, version: 1 }, innerEnum: { __kind: 'tokenTransfer', amount: BigInt(1), tokenType: { __kind: 'nFT', collection: 'DegenApes' }, }, innerStruct: { bytes: new Uint8Array([]), enumsArray: ['arm', 'arm'], name: 'nft-test', optionalPubkey: null, seedEnum: 'arm', value: BigInt(1), }, pubkey: pubkeyArg, seedEnum: 'arm', }, }) .accounts({ nestedExampleAccount, signer: payer }) .instruction(); await ctx.sendInstruction(ix, [payer]); expect(ix.data?.length).toBeGreaterThan(0); const exampleAccountData = ctx.requireEncodedAccount(nestedExampleAccount).data; const exampleAccount = decodeNestedExampleAccount(programClient.root, exampleAccountData); expect(exampleAccount.input).toEqual({ header: { command: { __kind: 'Start', fields: [42n], }, version: 1, }, innerEnum: { __kind: 'TokenTransfer', amount: 1n, tokenType: { __kind: 'NFT', collection: 'DegenApes' }, }, innerStruct: { bytes: bytesToBase16CodecFormat(new Uint8Array([])), enumsArray: [seedEnumToNumber('arm'), seedEnumToNumber('arm')], name: 'nft-test', optionalPubkey: none(), seedEnum: seedEnumToNumber('arm'), value: 1n, }, pubkey: pubkeyArg, seedEnum: seedEnumToNumber('arm'), }); }); test('should encode Stake inner enum and optional pubkey (Some)', async () => { const pubkeyArg = await ctx.createAccount(); const optionalPubkey = await ctx.createAccount(); const nestedExampleAccount = await deriveNestedExamplePda( programClient.programAddress, pubkeyArg, 'bar', 'car', ); const ix = await programClient.methods .nestedExample({ input: { header: { command: { __kind: 'start', fields: [321n] }, version: 3 }, innerEnum: { __kind: 'stake', duration: BigInt(86400) }, innerStruct: { bytes: new Uint8Array([10, 20]), enumsArray: ['bar', 'car'], name: 'staker', optionalPubkey, seedEnum: 'car', value: BigInt(42), }, pubkey: pubkeyArg, seedEnum: 'bar', }, }) .accounts({ nestedExampleAccount, signer: payer }) .instruction(); await ctx.sendInstruction(ix, [payer]); expect(ix.data?.length).toBeGreaterThan(0); const exampleAccountData = ctx.requireEncodedAccount(nestedExampleAccount).data; const exampleAccount = decodeNestedExampleAccount(programClient.root, exampleAccountData); expect(exampleAccount.input).toEqual({ header: { command: { __kind: 'Start', fields: [321n], }, version: 3, }, innerEnum: { __kind: 'Stake', duration: 86400n, }, innerStruct: { bytes: bytesToBase16CodecFormat(new Uint8Array([10, 20])), enumsArray: [seedEnumToNumber('bar'), seedEnumToNumber('car')], name: 'staker', optionalPubkey: some(optionalPubkey), seedEnum: seedEnumToNumber('car'), value: 42n, }, pubkey: pubkeyArg, seedEnum: seedEnumToNumber('bar'), }); }); describe('should validate nestedExampleIx arguments', () => { let pubkeyArg: Address; let nestedExampleAccount: Address; beforeEach(async () => { pubkeyArg = await ctx.createAccount(); nestedExampleAccount = await deriveNestedExamplePda(programClient.programAddress, pubkeyArg, 'arm', 'bar'); }); const makeValidArgs = (pubkey: Address): NestedExampleArgs['input'] => ({ header: { command: { __kind: 'start', fields: [123n] }, version: 1 }, innerEnum: { __kind: 'none' }, innerStruct: { bytes: new Uint8Array([1, 2, 3]), enumsArray: ['arm', 'car'], name: 'hello', optionalPubkey: null, seedEnum: 'bar', value: BigInt(100), }, pubkey, seedEnum: 'arm', }); test('should throw when input is missing', async () => { await expect( programClient.methods .nestedExample({} as unknown as NestedExampleArgs) .accounts({ nestedExampleAccount, signer: payer }) .instruction(), ).rejects.toThrow(/Invalid argument "input"/); }); test('should throw when header is missing', async () => { // eslint-disable-next-line @typescript-eslint/no-unused-vars const { header: _header, ...args } = makeValidArgs(pubkeyArg); await expect( programClient.methods .nestedExample({ input: args as unknown as NestedExampleArgs['input'], }) .accounts({ nestedExampleAccount, signer: payer }) .instruction(), ).rejects.toThrow(/Invalid argument "input.header"/); }); test('should throw when command enum fields tuple payload is missing', async () => { const input = makeValidArgs(pubkeyArg); input.header.command = { __kind: 'start', fields: null, } as unknown as NestedExampleArgs['input']['header']['command']; await expect( programClient.methods .nestedExample({ input, }) .accounts({ nestedExampleAccount, signer: payer }) .instruction(), ).rejects.toThrow(/Invalid argument "input.header.command"/); }); test('should throw when innerEnum payload data is missing', async () => { const input = makeValidArgs(pubkeyArg); input.innerEnum = { __kind: 'tokenTransfer', amount: BigInt(1), tokenType: { __kind: 'nFT', collection: 'Test' }, }; input.innerEnum.amount = undefined as unknown as bigint; // Force amount to be missing await expect( programClient.methods .nestedExample({ input, }) .accounts({ nestedExampleAccount, signer: payer }) .instruction(), ).rejects.toThrow(/Enum variant "tokenTransfer" has invalid "amount"/); }); test('should throw when tokenTransfer variant is missing all payload fields', async () => { const input = { ...makeValidArgs(pubkeyArg), innerEnum: { __kind: 'tokenTransfer' } as unknown as NestedExampleArgs['input']['innerEnum'], }; await expect( programClient.methods .nestedExample({ input }) .accounts({ nestedExampleAccount, signer: payer }) .instruction(), ).rejects.toThrow(/Enum variant "tokenTransfer" has invalid "amount"/); }); test('should throw when tokenTransfer variant is missing tokenType', async () => { const input = { ...makeValidArgs(pubkeyArg), innerEnum: { __kind: 'tokenTransfer', amount: BigInt(1), } as unknown as NestedExampleArgs['input']['innerEnum'], }; await expect( programClient.methods .nestedExample({ input }) .accounts({ nestedExampleAccount, signer: payer }) .instruction(), ).rejects.toThrow(/Enum variant "tokenTransfer" has invalid "tokenType"/); }); test('should throw when continue variant is missing reason', async () => { const input = { ...makeValidArgs(pubkeyArg), header: { command: { __kind: 'continue' } as unknown as NestedExampleArgs['input']['header']['command'], version: 1, }, }; await expect( programClient.methods .nestedExample({ input }) .accounts({ nestedExampleAccount, signer: payer }) .instruction(), ).rejects.toThrow(/Invalid argument "input.header.command".*"reason"/); }); test('should throw when innerStruct is missing', async () => { // eslint-disable-next-line @typescript-eslint/no-unused-vars const { innerStruct: _innerStruct, ...args } = makeValidArgs(pubkeyArg); await expect( programClient.methods .nestedExample({ input: args as unknown as NestedExampleArgs['input'], }) .accounts({ nestedExampleAccount, signer: payer }) .instruction(), ).rejects.toThrow(/Invalid argument "input.innerStruct"/); }); test('should throw when pubkey is missing', async () => { // eslint-disable-next-line @typescript-eslint/no-unused-vars const { pubkey: _pubkey, ...args } = makeValidArgs(pubkeyArg); await expect( programClient.methods .nestedExample({ input: args as unknown as NestedExampleArgs['input'], }) .accounts({ nestedExampleAccount, signer: payer }) .instruction(), ).rejects.toThrow(/Invalid argument "input.pubkey"/); }); test('should throw when header.version is string', async () => { const input = { ...makeValidArgs(pubkeyArg), header: { command: { __kind: 'start' }, version: 'one' as unknown as number }, } as unknown as NestedExampleArgs['input']; await expect( programClient.methods .nestedExample({ input, }) .accounts({ nestedExampleAccount, signer: payer }) .instruction(), ).rejects.toThrow(/Invalid argument "input.header.version"/); }); test('should throw when innerStruct.value is string', async () => { const validInput = makeValidArgs(pubkeyArg); const { innerStruct } = validInput; const input = { ...validInput, innerStruct: { ...innerStruct, value: 'hundred-of-thousands' as unknown as bigint, }, } as unknown as NestedExampleArgs['input']; await expect( programClient.methods .nestedExample({ input, }) .accounts({ nestedExampleAccount, signer: payer }) .instruction(), ).rejects.toThrow(/Invalid argument "input.innerStruct.value"/); }); test('should throw for invalid seedEnum variant', async () => { const input = { ...makeValidArgs(pubkeyArg), seedEnum: 'invalidVariant' as unknown as 'arm' }; await expect( programClient.methods .nestedExample({ input, }) .accounts({ nestedExampleAccount, signer: payer }) .instruction(), ).rejects.toThrow(/Invalid argument "input.seedEnum"/); }); test('should throw for invalid innerEnum __kind', async () => { const input = { ...makeValidArgs(pubkeyArg), innerEnum: { __kind: 'nonExistent' } as unknown as NestedExampleArgs['input']['innerEnum'], }; await expect( programClient.methods .nestedExample({ input, }) .accounts({ nestedExampleAccount, signer: payer }) .instruction(), ).rejects.toThrow(/Invalid argument "input.innerEnum"/); }); test('should throw for invalid header.command __kind', async () => { const input = { ...makeValidArgs(pubkeyArg), header: { command: { __kind: 'invalidCommand' } as unknown as NestedExampleArgs['input']['header']['command'], version: 1, }, }; await expect( programClient.methods .nestedExample({ input }) .accounts({ nestedExampleAccount, signer: payer }) .instruction(), ).rejects.toThrow(/Invalid argument "input.header.command"/); }); test('should throw when enumsArray has wrong size', async () => { const validInput = makeValidArgs(pubkeyArg); const { innerStruct } = validInput; const input = { ...makeValidArgs(pubkeyArg), innerStruct: { ...innerStruct, enumsArray: ['arm'] as unknown as ('arm' | 'bar' | 'car')[], }, }; await expect( programClient.methods .nestedExample({ input, }) .accounts({ nestedExampleAccount, signer: payer }) .instruction(), ).rejects.toThrow(/Invalid argument "input.innerStruct.enumsArray/); }); test('should throw when enumsArray has invalid enum value', async () => { const validInput = makeValidArgs(pubkeyArg); const { innerStruct } = validInput; const input = { ...makeValidArgs(pubkeyArg), innerStruct: { ...innerStruct, enumsArray: ['arm', 'invalid', 123] as unknown as ('arm' | 'bar' | 'car')[], }, }; await expect( programClient.methods .nestedExample({ input, }) .accounts({ nestedExampleAccount, signer: payer }) .instruction(), ).rejects.toThrow(/Invalid argument "input.innerStruct.enumsArray/); }); test('should throw when bytes is string instead of Uint8Array', async () => { const validInput = makeValidArgs(pubkeyArg); const { innerStruct } = validInput; const input = { ...makeValidArgs(pubkeyArg), innerStruct: { ...innerStruct, bytes: 'notbytes' as unknown as Uint8Array }, }; await expect( programClient.methods .nestedExample({ input, }) .accounts({ nestedExampleAccount, signer: payer }) .instruction(), ).rejects.toThrow(/Invalid argument "input.innerStruct.bytes"/); }); test('should throw for invalid pubkey string', async () => { const input = { ...makeValidArgs(pubkeyArg), pubkey: 'not-a-valid-address' as unknown as Address }; await expect( programClient.methods .nestedExample({ input }) .accounts({ nestedExampleAccount, signer: payer }) .instruction(), ).rejects.toThrow(/Invalid argument "input.pubkey"/); }); }); }); function decodeNestedExampleAccount(root: RootNode, data: Uint8Array) { const accountNode = root.program.accounts.find(a => a.name === 'nestedExampleAccount'); if (!accountNode) { throw new Error('Could not find account node "nestedExampleAccount" node in IDL'); } const codec = getNodeCodec([root, root.program, accountNode], { bytesEncoding: 'base16', }); const decoded = codec.decode(Uint8Array.from(data)); return decoded as { discriminator: unknown; input: unknown }; } async function deriveNestedExamplePda( programAddress: Address, pubkey: Address, seedEnum: 'arm' | 'bar' | 'car', innerSeedEnum: 'arm' | 'bar' | 'car', ): Promise
{ const index: Record = { arm: 0, bar: 1, car: 2 }; const [pda] = await getProgramDerivedAddress({ programAddress, seeds: [ 'nested_example_account', getAddressEncoder().encode(pubkey), new Uint8Array([index[seedEnum]]), new Uint8Array([index[innerSeedEnum]]), ], }); return pda; } /** SeedEnum enum is stored as a number. */ export function seedEnumToNumber(enumValue: string) { switch (enumValue.toLowerCase()) { case 'arm': return 0; case 'bar': return 1; case 'car': return 2; default: throw new Error(`Unknown enum value: ${enumValue}`); } } ================================================ FILE: packages/dynamic-client/test/programs/associated-token-account/ata-test-utils.ts ================================================ import type { Address } from '@solana/addresses'; import type { SplAssociatedTokenAccountProgramClient } from '../generated/associated-token-account-idl-types'; import type { SystemProgramClient } from '../generated/system-program-idl-types'; import type { TokenProgramClient } from '../generated/token-idl-types'; import { createTestProgramClient, SvmTestContext } from '../test-utils'; export const ataClient = createTestProgramClient( 'associated-token-account-idl.json', ); export const tokenClient = createTestProgramClient('token-idl.json'); export const systemClient = createTestProgramClient('system-program-idl.json'); const SPL_TOKEN_MINT_SIZE = 82n; export async function createMint( ctx: SvmTestContext, payer: Address, mint: Address, mintAuthority: Address, ): Promise { const lamports = ctx.getMinimumBalanceForRentExemption(SPL_TOKEN_MINT_SIZE); const createMintAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: tokenClient.programAddress, space: SPL_TOKEN_MINT_SIZE }) .accounts({ newAccount: mint, payer }) .instruction(); await ctx.sendInstruction(createMintAccountIx, [payer, mint]); const initializeMintIx = await tokenClient.methods .initializeMint({ decimals: 9, freezeAuthority: null, mintAuthority }) .accounts({ mint }) .instruction(); await ctx.sendInstruction(initializeMintIx, [payer]); } ================================================ FILE: packages/dynamic-client/test/programs/associated-token-account/create-idempotent.test.ts ================================================ import { findAssociatedTokenPda, getTokenDecoder } from '@solana-program/token'; import { beforeEach, describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { ataClient, createMint, tokenClient } from './ata-test-utils'; describe('Associated Token Account: createIdempotent', () => { let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext({ defaultPrograms: true }); }); test('should create an associated token account idempotently', async () => { const payer = await ctx.createFundedAccount(); const mintAuthority = await ctx.createFundedAccount(); const mint = await ctx.createAccount(); const wallet = await ctx.createFundedAccount(); await createMint(ctx, payer, mint, mintAuthority); const [ataAddress] = await findAssociatedTokenPda({ mint, owner: wallet, tokenProgram: tokenClient.programAddress, }); const ix = await ataClient.methods .createIdempotent() .accounts({ associatedAccountAddress: ataAddress, fundingAddress: payer, tokenMintAddress: mint, walletAddress: wallet, }) .instruction(); await ctx.sendInstruction(ix, [payer]); const ataAccount = ctx.requireEncodedAccount(ataAddress); const tokenData = getTokenDecoder().decode(ataAccount.data); expect(ataAccount.owner).toBe(tokenClient.programAddress); expect(tokenData.mint).toBe(mint); expect(tokenData.owner).toBe(wallet); // Call again — should succeed without error ctx.advanceSlots(); await ctx.sendInstruction(ix, [payer]); const ataAccountAfter = ctx.requireEncodedAccount(ataAddress); const tokenDataAfter = getTokenDecoder().decode(ataAccountAfter.data); expect(ataAccountAfter.owner).toBe(tokenClient.programAddress); expect(tokenDataAfter.mint).toBe(mint); expect(tokenDataAfter.owner).toBe(wallet); }); }); ================================================ FILE: packages/dynamic-client/test/programs/associated-token-account/create.test.ts ================================================ import { findAssociatedTokenPda, getTokenDecoder } from '@solana-program/token'; import { beforeEach, describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { ataClient, createMint, tokenClient } from './ata-test-utils'; describe('Associated Token Account: create', () => { let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext({ defaultPrograms: true }); }); test('should create an associated token account', async () => { const payer = await ctx.createFundedAccount(); const mintAuthority = await ctx.createFundedAccount(); const mint = await ctx.createAccount(); const wallet = await ctx.createFundedAccount(); await createMint(ctx, payer, mint, mintAuthority); const [ataAddress] = await findAssociatedTokenPda({ mint, owner: wallet, tokenProgram: tokenClient.programAddress, }); const ix = await ataClient.methods .create() .accounts({ associatedAccountAddress: ataAddress, fundingAddress: payer, tokenMintAddress: mint, walletAddress: wallet, }) .instruction(); await ctx.sendInstruction(ix, [payer]); const ataAccount = ctx.requireEncodedAccount(ataAddress); const tokenData = getTokenDecoder().decode(ataAccount.data); expect(ataAccount.owner).toBe(tokenClient.programAddress); expect(tokenData.mint).toBe(mint); expect(tokenData.owner).toBe(wallet); }); }); ================================================ FILE: packages/dynamic-client/test/programs/associated-token-account/recover-nested.test.ts ================================================ import { findAssociatedTokenPda, getTokenDecoder } from '@solana-program/token'; import { beforeEach, describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { ataClient, createMint, tokenClient } from './ata-test-utils'; describe('Associated Token Account: recoverNested', () => { let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext({ defaultPrograms: true }); }); test('should recover tokens from a nested associated token account', async () => { const payer = await ctx.createFundedAccount(); const mintAuthority = await ctx.createFundedAccount(); const ownerMint = await ctx.createAccount(); const nestedMint = await ctx.createAccount(); const wallet = await ctx.createFundedAccount(); await createMint(ctx, payer, ownerMint, mintAuthority); await createMint(ctx, payer, nestedMint, mintAuthority); // Create owner ATA (wallet → ownerMint) const [ownerAta] = await findAssociatedTokenPda({ mint: ownerMint, owner: wallet, tokenProgram: tokenClient.programAddress, }); const createOwnerAtaIx = await ataClient.methods .create() .accounts({ associatedAccountAddress: ownerAta, fundingAddress: payer, tokenMintAddress: ownerMint, walletAddress: wallet, }) .instruction(); await ctx.sendInstruction(createOwnerAtaIx, [payer]); // Create nested ATA (ownerAta → nestedMint) — tokens sent here accidentally const [nestedAta] = await findAssociatedTokenPda({ mint: nestedMint, owner: ownerAta, tokenProgram: tokenClient.programAddress, }); const createNestedAtaIx = await ataClient.methods .create() .accounts({ associatedAccountAddress: nestedAta, fundingAddress: payer, tokenMintAddress: nestedMint, walletAddress: ownerAta, }) .instruction(); await ctx.sendInstruction(createNestedAtaIx, [payer]); // Mint tokens to nested ATA const amount = BigInt(1_000_000); const mintToIx = await tokenClient.methods .mintTo({ amount }) .accounts({ mint: nestedMint, mintAuthority, token: nestedAta }) .signers(['mintAuthority']) .instruction(); await ctx.sendInstruction(mintToIx, [payer, mintAuthority]); // Create destination ATA (wallet → nestedMint) const [destinationAta] = await findAssociatedTokenPda({ mint: nestedMint, owner: wallet, tokenProgram: tokenClient.programAddress, }); const createDestAtaIx = await ataClient.methods .create() .accounts({ associatedAccountAddress: destinationAta, fundingAddress: payer, tokenMintAddress: nestedMint, walletAddress: wallet, }) .instruction(); await ctx.sendInstruction(createDestAtaIx, [payer]); // Recover nested tokens const recoverIx = await ataClient.methods .recoverNested() .accounts({ destinationAssociatedAccountAddress: destinationAta, nestedAssociatedAccountAddress: nestedAta, nestedTokenMintAddress: nestedMint, ownerAssociatedAccountAddress: ownerAta, ownerTokenMintAddress: ownerMint, walletAddress: wallet, }) .signers(['walletAddress']) .instruction(); await ctx.sendInstruction(recoverIx, [payer, wallet]); // Verify tokens moved to destination const destAccount = ctx.requireEncodedAccount(destinationAta); const destTokenData = getTokenDecoder().decode(destAccount.data); expect(destTokenData.amount).toBe(amount); }); }); ================================================ FILE: packages/dynamic-client/test/programs/circular-account-refs/circular-account-refs.test.ts ================================================ import { address } from '@solana/addresses'; import { describe, expect, test } from 'vitest'; import type { CircularAccountRefsProgramClient } from '../generated/circular-account-refs-idl-types'; import { createTestProgramClient } from '../test-utils'; describe('Circular Account References (Without PDA Seeds)', () => { const programClient = createTestProgramClient('circular-account-refs-idl.json'); test('should throw AccountError for A->A self-reference', async () => { await expect(programClient.methods.selfReference().accounts({}).instruction()).rejects.toThrow( /Circular dependency detected: \[accountA -> accountA\]/, ); }); test('should throw AccountError for A->B->A two-node cycle', async () => { await expect(programClient.methods.twoAccountCycle().accounts({}).instruction()).rejects.toThrow( /Circular dependency detected: \[account(A|B) -> account(A|B) -> account(A|B)\]/, ); }); test('should throw AccountError for A->B->C->A three-node cycle', async () => { await expect(programClient.methods.threeAccountCycle().accounts({}).instruction()).rejects.toThrow( /Circular dependency detected: \[account(A|B|C) -> account(A|B|C) -> account(A|B|C) -> account(A|B|C)\]/, ); }); test('should succeed when account is provided (A->B->A cycle)', async () => { const testAddress = address('HNvDDMNXFUkJz8fFDVJ2GLrWNWYcFfqjJWJZR7JSxaMv'); const ixWithA = await programClient.methods.twoAccountCycle().accounts({ accountA: testAddress }).instruction(); const ixWithB = await programClient.methods.twoAccountCycle().accounts({ accountB: testAddress }).instruction(); [ixWithA, ixWithB].forEach(ix => { expect(ix.accounts?.length).toBe(2); ix.accounts?.forEach(account => { expect(account.address).toBe(testAddress); }); }); }); test('should succeed when account in three-node cycle (A->B->C->A) is provided', async () => { const testAddress = address('HNvDDMNXFUkJz8fFDVJ2GLrWNWYcFfqjJWJZR7JSxaMv'); const ixWithA = await programClient.methods .threeAccountCycle() .accounts({ accountA: testAddress }) .instruction(); const ixWithB = await programClient.methods .threeAccountCycle() .accounts({ accountB: testAddress }) .instruction(); const ixWithC = await programClient.methods .threeAccountCycle() .accounts({ accountC: testAddress }) .instruction(); [ixWithA, ixWithB, ixWithC].forEach(ix => { expect(ix.accounts?.length).toBe(3); ix.accounts?.forEach(account => { expect(account.address).toBe(testAddress); }); }); }); test('should provide account self-reference', async () => { const testAddress = address('HNvDDMNXFUkJz8fFDVJ2GLrWNWYcFfqjJWJZR7JSxaMv'); const ix = await programClient.methods.selfReference().accounts({ accountA: testAddress }).instruction(); expect(ix.accounts?.length).toBe(1); expect(ix?.accounts?.[0]?.address).toBe(testAddress); }); }); ================================================ FILE: packages/dynamic-client/test/programs/collection-types/collection-types.test.ts ================================================ import { getNodeCodec, type ReadonlyUint8Array } from '@codama/dynamic-codecs'; import { type Address } from '@solana/addresses'; import { beforeEach, describe, expect, test } from 'vitest'; import type { CollectionTypesProgramClient } from '../generated/collection-types-idl-types'; import { createTestProgramClient, loadRoot, SvmTestContext } from '../test-utils'; const root = loadRoot('collection-types-idl.json'); function decodeInstructionData(instructionName: string, data: ReadonlyUint8Array): unknown { const ix = root.program.instructions.find(i => i.name === instructionName); if (!ix) throw new Error(`Instruction ${instructionName} not found`); const codec = getNodeCodec([root, root.program, ix]); return codec.decode(new Uint8Array(data)); } describe('Collection types: encoding and validation (set, map, tuple)', () => { let ctx: SvmTestContext; let signer: Address; const programClient = createTestProgramClient('collection-types-idl.json'); beforeEach(async () => { ctx = new SvmTestContext({ defaultPrograms: true, sysvars: true }); signer = await ctx.createFundedAccount(); }); describe('tupleTypeNode', () => { test('should build instruction with basic tuple [u64, string]', async () => { const ix = await programClient.methods .storeTuple({ data: [42n, 'hello'] }) .accounts({ signer }) .instruction(); const decoded = decodeInstructionData('storeTuple', ix.data!); expect(decoded).toMatchObject({ data: [42n, 'hello'], discriminator: 0, }); }); test('should build instruction with nested tuple [map, array]', async () => { const ix = await programClient.methods .storeNestedTuple({ data: [{ alice: 100n, bob: 200n }, [1n, 2n, 3n]], }) .accounts({ signer }) .instruction(); const decoded = decodeInstructionData('storeNestedTuple', ix.data!); expect(decoded).toMatchObject({ data: [{ alice: 100n, bob: 200n }, [1n, 2n, 3n]], discriminator: 6, }); }); test('should reject tuple with wrong length', async () => { await expect( programClient.methods // @ts-expect-error - testing wrong tuple length .storeTuple({ data: [42n] }) .accounts({ signer }) .instruction(), ).rejects.toThrow(/Invalid argument "data\[1\]", value: undefined/); }); test('should reject tuple with wrong item type', async () => { await expect( programClient.methods // @ts-expect-error - testing wrong item type .storeTuple({ data: [42n, 123] }) .accounts({ signer }) .instruction(), ).rejects.toThrow(/Invalid argument "data\[1\]", value: 123/); }); }); describe('mapTypeNode', () => { test('should build instruction with basic map ([string]: u64)', async () => { const ix = await programClient.methods .storeMap({ data: { alice: 100n, bob: 200n, charlie: 300n } }) .accounts({ signer }) .instruction(); const decoded = decodeInstructionData('storeMap', ix.data!); expect(decoded).toMatchObject({ data: { alice: 100n, bob: 200n, charlie: 300n }, discriminator: 1, }); }); test('should build instruction with empty map', async () => { const ix = await programClient.methods.storeMap({ data: {} }).accounts({ signer }).instruction(); const decoded = decodeInstructionData('storeMap', ix.data!); expect(decoded).toMatchObject({ data: {}, discriminator: 1, }); }); test('should build instruction with nested map ([string]: array)', async () => { const ix = await programClient.methods .storeNestedMap({ data: { list1: [1n, 2n, 3n], list2: [10n, 20n], list3: [], }, }) .accounts({ signer }) .instruction(); const decoded = decodeInstructionData('storeNestedMap', ix.data!); expect(decoded).toMatchObject({ data: { list1: [1n, 2n, 3n], list2: [10n, 20n], list3: [], }, discriminator: 7, }); }); test('should reject non-object input', async () => { await expect( programClient.methods // @ts-expect-error - testing non-object input .storeMap({ data: [1, 2, 3] }) .accounts({ signer }) .instruction(), ).rejects.toThrow(/Expected \[object\] for \[mapTypeNode\]/); }); test('should reject wrong value type', async () => { await expect( programClient.methods // @ts-expect-error - testing wrong value type .storeMap({ data: { key: 'wrong' } }) .accounts({ signer }) .instruction(), ).rejects.toThrow(/Invalid argument "data"/); }); }); describe('setTypeNode', () => { test('should build instruction with basic set', async () => { const ix = await programClient.methods .storeSet({ data: [1n, 2n, 3n] }) .accounts({ signer }) .instruction(); const decoded = decodeInstructionData('storeSet', ix.data!); expect(decoded).toMatchObject({ data: [1n, 2n, 3n], discriminator: 2, }); }); test('should build instruction with empty set', async () => { const ix = await programClient.methods.storeSet({ data: [] }).accounts({ signer }).instruction(); const decoded = decodeInstructionData('storeSet', ix.data!); expect(decoded).toMatchObject({ data: [], discriminator: 2, }); }); test('should build instruction with nested set>', async () => { const ix = await programClient.methods .storeNestedSet({ data: [ [1n, 'first'], [2n, 'second'], [3n, 'third'], [3n, 'fifth'], ], }) .accounts({ signer }) .instruction(); const decoded = decodeInstructionData('storeNestedSet', ix.data!); expect(decoded).toMatchObject({ data: [ [1n, 'first'], [2n, 'second'], [3n, 'third'], [3n, 'fifth'], ], discriminator: 8, }); }); test('should reject duplicate primitive values in set', async () => { await expect( programClient.methods .storeSet({ data: [1n, 2n, 1n] }) .accounts({ signer }) .instruction(), ).rejects.toThrow(/Expected all items to be unique/); await expect( programClient.methods .storeNestedSet({ data: [ [1n, 'first'], [2n, 'second'], [1n, 'first'], // duplicate ], }) .accounts({ signer }) .instruction(), ).rejects.toThrow(/Expected all items to be unique/); }); test('should reject non-array input', async () => { await expect( programClient.methods // @ts-expect-error - testing non-array input .storeSet({ data: { key: 'value' } }) .accounts({ signer }) .instruction(), ).rejects.toThrow(/Invalid argument "data"/); }); test('should reject non-serializable input with a helpful validation error', async () => { const invalidData: Record = { a: 1n, b: {} }; invalidData.b = invalidData; await expect( programClient.methods // @ts-expect-error - testing circular reference input .storeSet({ data: [invalidData, invalidData] }) .accounts({ signer }) .instruction(), ).rejects.toThrow(/Invalid argument "data", value: non-serializable array \(length 2\)/); }); }); }); ================================================ FILE: packages/dynamic-client/test/programs/custom-resolvers/account-resolver.test.ts ================================================ import type { Address } from '@solana/addresses'; import { beforeEach, describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { programClient } from './custom-resolvers-test-utils'; describe('Custom resolvers: accounts ResolverValueNode', () => { let authority: Address; let ctx: SvmTestContext; beforeEach(async () => { ctx = new SvmTestContext(); authority = await ctx.createFundedAccount(); }); test('should resolve accounts addresses via resolver', async () => { const destination = await ctx.createFundedAccount(); const treasury = await ctx.createFundedAccount(); const expectedAccounts = [authority, destination, treasury]; const ix = await programClient.methods .transferWithResolver({ amount: 100 }) .accounts({ authority }) .resolvers({ resolveDestination: () => Promise.resolve(destination), resolveTreasury: () => Promise.resolve(treasury), }) .instruction(); expect(ix.accounts?.length).toBe(3); ix.accounts?.forEach((accountMeta, index) => { expect(accountMeta.address).toBe(expectedAccounts[index]); }); }); test('should throw AccountError when resolver missing for required account', async () => { await expect( programClient.methods.transferWithResolver({ amount: 100 }).accounts({ authority }).instruction(), ).rejects.toThrow(/Resolver \[resolveDestination\] not provided for account \[destination\]/); }); test('should throw AccountError when resolver returns null/undefined for required account', async () => { const treasury = await ctx.createAccount(); await expect( programClient.methods .transferWithResolver({ amount: 100 }) .accounts({ authority, treasury }) .resolvers({ resolveDestination: () => Promise.resolve(null), }) .instruction(), ).rejects.toThrow(/Invalid account address \[destination\]: \[null\]/); await expect( programClient.methods .transferWithResolver({ amount: 100 }) .accounts({ authority, treasury }) .resolvers({ resolveDestination: () => Promise.resolve(undefined), }) .instruction(), ).rejects.toThrow(/Invalid account address \[destination\]: \[undefined\]/); }); test('should propagate error when account resolver rejects', async () => { await expect( programClient.methods .transferWithResolver({ amount: 100 }) .accounts({ authority }) .resolvers({ resolveDestination: () => Promise.reject(new Error('resolver failed')), resolveTreasury: () => Promise.resolve(ctx.SYSTEM_PROGRAM_ADDRESS), }) .instruction(), ).rejects.toThrow( /Resolver \[resolveDestination\] threw an error while resolving \[instructionAccountNode\] \[destination\]/, ); }); test('should throw when resolver missing for optional undefined account with direct resolverValueNode', async () => { const destination = await ctx.createFundedAccount(); await expect( programClient.methods .transferWithResolver({ amount: 100 }) .accounts({ authority }) .resolvers({ resolveDestination: () => Promise.resolve(destination), }) .instruction(), ).rejects.toThrow(/Resolver \[resolveTreasury\] not provided for account \[treasury\]/); // double-check: when we provide null, treasury will be resolved into programId even without resolveTreasury resolver. const ix = await programClient.methods .transferWithResolver({ amount: 100 }) .accounts({ authority, treasury: null }) .resolvers({ resolveDestination: () => Promise.resolve(destination), }) .instruction(); expect(ix.accounts?.[2].address).toBe(programClient.programAddress); }); test('should bypass resolver when account is explicitly provided', async () => { const destination = await ctx.createAccount(); const treasury = await ctx.createAccount(); const ix = await programClient.methods .transferWithResolver({ amount: 42 }) .accounts({ authority, destination, treasury }) .resolvers({ resolveDestination: () => { throw new Error('resolveDestination should not be called'); }, resolveTreasury: () => { throw new Error('resolveTreasury should not be called'); }, }) .instruction(); expect(ix.accounts?.[1].address).toBe(destination); expect(ix.accounts?.[2].address).toBe(treasury); }); test('should resolve to programId when resolver returns null', async () => { const ix = await programClient.methods .conditionalTransfer() .accounts({ authority }) .resolvers({ resolveIncludeRequired: () => Promise.resolve(true), resolveIncludeTarget: () => Promise.resolve(null), }) .instruction(); expect(ix.accounts?.[1].address).toBe(programClient.programAddress); }); test('should throw AccountError when omitted required account conditional has no ifFalse and condition is falsy', async () => { await expect( programClient.methods .conditionalTransfer() .accounts({ authority }) .resolvers({ resolveIncludeRequired: () => Promise.resolve(false), resolveIncludeTarget: () => Promise.resolve(true), }) .instruction(), ).rejects.toThrow(/Missing account \[requiredTarget\] in \[conditionalTransfer\] instruction/); }); }); ================================================ FILE: packages/dynamic-client/test/programs/custom-resolvers/argument-resolvers.test.ts ================================================ import type { Address } from '@solana/addresses'; import { addEncoderSizePrefix, getOptionEncoder, getU8Encoder, getU32Encoder, getUtf8Encoder, none, some, } from '@solana/codecs'; import { beforeEach, describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { programClient } from './custom-resolvers-test-utils'; const utf8Encoder = getUtf8Encoder(); const u32Encoder = getU32Encoder(); const u8Encoder = getU8Encoder(); const stringEncoder = addEncoderSizePrefix(utf8Encoder, u32Encoder); /** * Concat arguments for createItem ix data bytes: * [discriminator: u8] + [name: utf8] + [description: optional(utf8)] + [tags: optional(u8)] */ function expectedData({ name, description, tags, }: { description?: string | null; name: string; tags?: number | null; }): Uint8Array { const discriminator = new Uint8Array([8]); const nameBytes = stringEncoder.encode(name); const descriptionBytes = getOptionEncoder(stringEncoder).encode(description ? some(description) : none()); const tagsBytes = getOptionEncoder(u8Encoder).encode(tags ? some(tags) : none()); return new Uint8Array([...discriminator, ...nameBytes, ...descriptionBytes, ...tagsBytes]); } describe('Custom resolvers: arguments ResolverValueNode', () => { let authority: Address; let ctx: SvmTestContext; beforeEach(async () => { ctx = new SvmTestContext(); authority = await ctx.createFundedAccount(); }); test('should resolve omitted argument via resolver', async () => { const ix = await programClient.methods .createItem({ name: 'hello' }) .accounts({ authority }) .resolvers({ resolveDescription: () => Promise.resolve('auto-filled') }) .instruction(); expect(ix.data).toEqual(expectedData({ description: 'auto-filled', name: 'hello', tags: null })); }); test('should bypass resolver when argument is explicitly provided', async () => { const ix = await programClient.methods .createItem({ description: 'explicit', name: 'hello' }) .accounts({ authority }) .resolvers({ resolveDescription: () => { throw new Error('should not be called'); }, }) .instruction(); expect(ix.data).toEqual(expectedData({ description: 'explicit', name: 'hello', tags: null })); }); test('should call multiple resolvers independently', async () => { const ix = await programClient.methods .createItem({ name: 'multi' }) .accounts({ authority }) .resolvers({ resolveDescription: () => Promise.resolve('desc'), resolveTags: () => Promise.resolve(42), }) .instruction(); expect(ix.data).toEqual(expectedData({ description: 'desc', name: 'multi', tags: 42 })); }); test('should pass argumentsInput and accountsInput context to resolver', async () => { const expectedArgs = { name: 'context' }; const expectedAccounts = { authority }; const capturedArgs: Record = {}; const capturedAccounts: Record = {}; await programClient.methods .createItem(expectedArgs) .accounts(expectedAccounts) .resolvers({ resolveDescription: (args, accounts) => { Object.assign(capturedArgs, args); Object.assign(capturedAccounts, accounts); return Promise.resolve(null); }, }) .instruction(); expect(capturedArgs).toEqual(expectedArgs); expect(capturedAccounts).toEqual(expectedAccounts); }); test('should omit optional argument when no resolver provided', async () => { const ix = await programClient.methods .createItem({ name: 'no-resolver' }) .accounts({ authority }) .instruction(); expect(ix.data).toEqual(expectedData({ description: null, name: 'no-resolver', tags: null })); }); test('should propagate error when argument resolver throws', async () => { await expect( programClient.methods .createItem({ name: 'err' }) .accounts({ authority }) .resolvers({ resolveDescription: () => { throw new Error('Error from resolver'); }, }) .instruction(), ).rejects.toThrow( /Resolver \[resolveDescription\] threw an error while resolving \[instructionArgumentNode\] \[description\]/, ); await expect( programClient.methods .createItem({ name: 'err' }) .accounts({ authority }) .resolvers({ resolveDescription: () => Promise.reject(new Error('Async error from resolver')), }) .instruction(), ).rejects.toThrow( /Resolver \[resolveDescription\] threw an error while resolving \[instructionArgumentNode\] \[description\]/, ); }); test('should encode optional argument as none when resolver returns undefined or null', async () => { const ix1 = await programClient.methods .createItem({ name: 'hello world 1' }) .accounts({ authority }) .resolvers({ resolveDescription: () => Promise.resolve(undefined) }) .instruction(); expect(ix1.data).toEqual(expectedData({ description: null, name: 'hello world 1', tags: null })); const ix2 = await programClient.methods .createItem({ name: 'hello world 2' }) .accounts({ authority }) .resolvers({ resolveDescription: () => Promise.resolve(null) }) .instruction(); expect(ix2.data).toEqual(expectedData({ description: null, name: 'hello world 2', tags: null })); }); }); ================================================ FILE: packages/dynamic-client/test/programs/custom-resolvers/custom-resolvers-test-utils.ts ================================================ import { type CustomResolversTestProgramClient } from '../generated/custom-resolvers-test-idl-types'; import { createTestProgramClient } from '../test-utils'; export const programClient = createTestProgramClient( 'custom-resolvers-test-idl.json', ); ================================================ FILE: packages/dynamic-client/test/programs/idls/associated-token-account-idl.json ================================================ { "kind": "rootNode", "standard": "codama", "version": "1.3.7", "program": { "kind": "programNode", "name": "splAssociatedTokenAccount", "publicKey": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", "version": "1.1.1", "docs": [], "accounts": [], "instructions": [ { "kind": "instructionNode", "name": "create", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "fundingAddress", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "associatedAccountAddress", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "walletAddress", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "tokenMintAddress", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "tokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 0 }, "defaultValueStrategy": "omitted" } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "createIdempotent", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "fundingAddress", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "associatedAccountAddress", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "walletAddress", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "tokenMintAddress", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "tokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 1 }, "defaultValueStrategy": "omitted" } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "recoverNested", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "nestedAssociatedAccountAddress", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "nestedTokenMintAddress", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "destinationAssociatedAccountAddress", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "ownerAssociatedAccountAddress", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "ownerTokenMintAddress", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "walletAddress", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "tokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 2 }, "defaultValueStrategy": "omitted" } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] } ], "definedTypes": [], "pdas": [], "errors": [ { "kind": "errorNode", "name": "invalidOwner", "code": 0, "message": "Associated token account owner does not match address derivation", "docs": ["InvalidOwner: Associated token account owner does not match address derivation"] } ] }, "additionalPrograms": [] } ================================================ FILE: packages/dynamic-client/test/programs/idls/blog-idl.json ================================================ { "kind": "rootNode", "standard": "codama", "version": "1.5.1", "program": { "kind": "programNode", "name": "blog", "publicKey": "1rAs9KgDjEnMVrU1nJPWVhN4b6W4VEBxzcNJoeJpbVR", "version": "0.1.0", "origin": "anchor", "docs": [], "accounts": [ { "kind": "accountNode", "name": "accessGrant", "size": 45, "docs": [], "data": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "fixedSizeTypeNode", "size": 8, "type": { "kind": "bytesTypeNode" } }, "defaultValue": { "kind": "bytesValueNode", "data": "a737b8ed4af2006d", "encoding": "base16" } }, { "kind": "structFieldTypeNode", "name": "profile", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "permissions", "docs": [], "type": { "kind": "fixedSizeTypeNode", "size": 4, "type": { "kind": "bytesTypeNode" } } }, { "kind": "structFieldTypeNode", "name": "bump", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } ] }, "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "accountNode", "name": "bookmarkList", "docs": [], "data": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "fixedSizeTypeNode", "size": 8, "type": { "kind": "bytesTypeNode" } }, "defaultValue": { "kind": "bytesValueNode", "data": "a166250186ff7035", "encoding": "base16" } }, { "kind": "structFieldTypeNode", "name": "owner", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "bookmarks", "docs": [], "type": { "kind": "arrayTypeNode", "item": { "kind": "publicKeyTypeNode" }, "count": { "kind": "prefixedCountNode", "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } } }, { "kind": "structFieldTypeNode", "name": "bump", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } ] }, "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "accountNode", "name": "category", "docs": [], "data": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "fixedSizeTypeNode", "size": 8, "type": { "kind": "bytesTypeNode" } }, "defaultValue": { "kind": "bytesValueNode", "data": "f223f5e8dde36234", "encoding": "base16" } }, { "kind": "structFieldTypeNode", "name": "creator", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "name", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "bump", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } ] }, "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "accountNode", "name": "dailyDigest", "size": 46, "docs": [], "data": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "fixedSizeTypeNode", "size": 8, "type": { "kind": "bytesTypeNode" } }, "defaultValue": { "kind": "bytesValueNode", "data": "9f7a552333dbba01", "encoding": "base16" } }, { "kind": "structFieldTypeNode", "name": "profile", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "year", "docs": [], "type": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "month", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "day", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "postCount", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "bump", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } ] }, "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "accountNode", "name": "post", "docs": [], "data": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "fixedSizeTypeNode", "size": 8, "type": { "kind": "bytesTypeNode" } }, "defaultValue": { "kind": "bytesValueNode", "data": "08935abab938c096", "encoding": "base16" } }, { "kind": "structFieldTypeNode", "name": "author", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "id", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "title", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "content", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "bump", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } ] }, "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "accountNode", "name": "profile", "docs": [], "data": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "fixedSizeTypeNode", "size": 8, "type": { "kind": "bytesTypeNode" } }, "defaultValue": { "kind": "bytesValueNode", "data": "b865a5bc5f3f7fbc", "encoding": "base16" } }, { "kind": "structFieldTypeNode", "name": "authority", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "username", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "postCount", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "bump", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } ] }, "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "accountNode", "name": "reaction", "size": 74, "docs": [], "data": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "fixedSizeTypeNode", "size": 8, "type": { "kind": "bytesTypeNode" } }, "defaultValue": { "kind": "bytesValueNode", "data": "e23d64bfdfdd8e8b", "encoding": "base16" } }, { "kind": "structFieldTypeNode", "name": "post", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "user", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "kind", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "bump", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } ] }, "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "accountNode", "name": "subscription", "size": 73, "docs": [], "data": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "fixedSizeTypeNode", "size": 8, "type": { "kind": "bytesTypeNode" } }, "defaultValue": { "kind": "bytesValueNode", "data": "40071a8766846221", "encoding": "base16" } }, { "kind": "structFieldTypeNode", "name": "follower", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "author", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "bump", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } ] }, "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] } ], "instructions": [ { "kind": "instructionNode", "name": "createAccessGrant", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "authority", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "profile", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "profile" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "authority", "value": { "kind": "accountValueNode", "name": "authority" } } ] } }, { "kind": "instructionAccountNode", "name": "accessGrant", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "accessGrant" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "profile", "value": { "kind": "accountValueNode", "name": "profile" } }, { "kind": "pdaSeedValueNode", "name": "permissions", "value": { "kind": "argumentValueNode", "name": "permissions" } } ] } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "systemProgram" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "fixedSizeTypeNode", "size": 8, "type": { "kind": "bytesTypeNode" } }, "defaultValue": { "kind": "bytesValueNode", "data": "480b9806c737599e", "encoding": "base16" } }, { "kind": "instructionArgumentNode", "name": "permissions", "docs": [], "type": { "kind": "fixedSizeTypeNode", "size": 4, "type": { "kind": "bytesTypeNode" } } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "createBookmarkList", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "owner", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "bookmarkList", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "bookmarkList" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "accountValueNode", "name": "owner" } } ] } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "systemProgram" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "fixedSizeTypeNode", "size": 8, "type": { "kind": "bytesTypeNode" } }, "defaultValue": { "kind": "bytesValueNode", "data": "778dbfdea33e1da9", "encoding": "base16" } }, { "kind": "instructionArgumentNode", "name": "bookmarks", "docs": [], "type": { "kind": "arrayTypeNode", "item": { "kind": "publicKeyTypeNode" }, "count": { "kind": "prefixedCountNode", "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "createCategory", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "creator", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "category", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "category" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "name", "value": { "kind": "argumentValueNode", "name": "name" } } ] } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "systemProgram" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "fixedSizeTypeNode", "size": 8, "type": { "kind": "bytesTypeNode" } }, "defaultValue": { "kind": "bytesValueNode", "data": "dcf2ee2fe4dbdfe6", "encoding": "base16" } }, { "kind": "instructionArgumentNode", "name": "name", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "createDailyDigest", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "authority", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "profile", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "profile" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "authority", "value": { "kind": "accountValueNode", "name": "authority" } } ] } }, { "kind": "instructionAccountNode", "name": "dailyDigest", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "dailyDigest" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "profile", "value": { "kind": "accountValueNode", "name": "profile" } }, { "kind": "pdaSeedValueNode", "name": "year", "value": { "kind": "argumentValueNode", "name": "year" } }, { "kind": "pdaSeedValueNode", "name": "month", "value": { "kind": "argumentValueNode", "name": "month" } }, { "kind": "pdaSeedValueNode", "name": "day", "value": { "kind": "argumentValueNode", "name": "day" } } ] } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "systemProgram" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "fixedSizeTypeNode", "size": 8, "type": { "kind": "bytesTypeNode" } }, "defaultValue": { "kind": "bytesValueNode", "data": "39b9aea36467fe8d", "encoding": "base16" } }, { "kind": "instructionArgumentNode", "name": "year", "docs": [], "type": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } }, { "kind": "instructionArgumentNode", "name": "month", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, { "kind": "instructionArgumentNode", "name": "day", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "createPost", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "authority", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "profile", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "profile" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "authority", "value": { "kind": "accountValueNode", "name": "authority" } } ] } }, { "kind": "instructionAccountNode", "name": "post", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "systemProgram" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "fixedSizeTypeNode", "size": 8, "type": { "kind": "bytesTypeNode" } }, "defaultValue": { "kind": "bytesValueNode", "data": "7b5cb81de7180fca", "encoding": "base16" } }, { "kind": "instructionArgumentNode", "name": "title", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "instructionArgumentNode", "name": "content", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "createProfile", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "authority", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "profile", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "profile" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "authority", "value": { "kind": "accountValueNode", "name": "authority" } } ] } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "systemProgram" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "fixedSizeTypeNode", "size": 8, "type": { "kind": "bytesTypeNode" } }, "defaultValue": { "kind": "bytesValueNode", "data": "e1cdea8f11ba32dc", "encoding": "base16" } }, { "kind": "instructionArgumentNode", "name": "username", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "react", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "user", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "post", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "reaction", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "reaction" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "post", "value": { "kind": "accountValueNode", "name": "post" } }, { "kind": "pdaSeedValueNode", "name": "user", "value": { "kind": "accountValueNode", "name": "user" } }, { "kind": "pdaSeedValueNode", "name": "kind", "value": { "kind": "argumentValueNode", "name": "kind" } } ] } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "systemProgram" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "fixedSizeTypeNode", "size": 8, "type": { "kind": "bytesTypeNode" } }, "defaultValue": { "kind": "bytesValueNode", "data": "1e3377485425cccf", "encoding": "base16" } }, { "kind": "instructionArgumentNode", "name": "kind", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "subscribe", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "follower", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "author", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "subscription", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "subscription" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "follower", "value": { "kind": "accountValueNode", "name": "follower" } }, { "kind": "pdaSeedValueNode", "name": "author", "value": { "kind": "accountValueNode", "name": "author" } } ] } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "systemProgram" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "fixedSizeTypeNode", "size": 8, "type": { "kind": "bytesTypeNode" } }, "defaultValue": { "kind": "bytesValueNode", "data": "fe1cbf8a9cb3b735", "encoding": "base16" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "updatePost", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": [], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "profile", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "profile" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "authority", "value": { "kind": "accountValueNode", "name": "authority" } } ] } }, { "kind": "instructionAccountNode", "name": "post", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "post" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "profile", "value": { "kind": "accountValueNode", "name": "profile" } }, { "kind": "pdaSeedValueNode", "name": "postId", "value": { "kind": "argumentValueNode", "name": "postId" } } ] } }, { "kind": "instructionAccountNode", "name": "author", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "fixedSizeTypeNode", "size": 8, "type": { "kind": "bytesTypeNode" } }, "defaultValue": { "kind": "bytesValueNode", "data": "9780cf6ba9f6f16b", "encoding": "base16" } }, { "kind": "instructionArgumentNode", "name": "postId", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, { "kind": "instructionArgumentNode", "name": "title", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "instructionArgumentNode", "name": "content", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] } ], "definedTypes": [], "pdas": [ { "kind": "pdaNode", "name": "profile", "docs": [], "seeds": [ { "kind": "constantPdaSeedNode", "type": { "kind": "bytesTypeNode" }, "value": { "kind": "bytesValueNode", "data": "5G9odWBzmA", "encoding": "base58" } }, { "kind": "variablePdaSeedNode", "name": "authority", "docs": [], "type": { "kind": "publicKeyTypeNode" } } ] }, { "kind": "pdaNode", "name": "accessGrant", "docs": [], "seeds": [ { "kind": "constantPdaSeedNode", "type": { "kind": "bytesTypeNode" }, "value": { "kind": "bytesValueNode", "data": "CfvKowZ", "encoding": "base58" } }, { "kind": "variablePdaSeedNode", "name": "profile", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "variablePdaSeedNode", "name": "permissions", "docs": [], "type": { "kind": "fixedSizeTypeNode", "size": 4, "type": { "kind": "bytesTypeNode" } } } ] }, { "kind": "pdaNode", "name": "bookmarkList", "docs": [], "seeds": [ { "kind": "constantPdaSeedNode", "type": { "kind": "bytesTypeNode" }, "value": { "kind": "bytesValueNode", "data": "2Ffw66YXmcbBp", "encoding": "base58" } }, { "kind": "variablePdaSeedNode", "name": "owner", "docs": [], "type": { "kind": "publicKeyTypeNode" } } ] }, { "kind": "pdaNode", "name": "category", "docs": [], "seeds": [ { "kind": "constantPdaSeedNode", "type": { "kind": "bytesTypeNode" }, "value": { "kind": "bytesValueNode", "data": "Hd7nx8Jz9DA", "encoding": "base58" } }, { "kind": "variablePdaSeedNode", "name": "name", "docs": [], "type": { "kind": "stringTypeNode", "encoding": "utf8" } } ] }, { "kind": "pdaNode", "name": "dailyDigest", "docs": [], "seeds": [ { "kind": "constantPdaSeedNode", "type": { "kind": "bytesTypeNode" }, "value": { "kind": "bytesValueNode", "data": "s186r9EB", "encoding": "base58" } }, { "kind": "variablePdaSeedNode", "name": "profile", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "variablePdaSeedNode", "name": "year", "docs": [], "type": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } }, { "kind": "variablePdaSeedNode", "name": "month", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, { "kind": "variablePdaSeedNode", "name": "day", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } ] }, { "kind": "pdaNode", "name": "reaction", "docs": [], "seeds": [ { "kind": "constantPdaSeedNode", "type": { "kind": "bytesTypeNode" }, "value": { "kind": "bytesValueNode", "data": "L8nWcjTPk4d", "encoding": "base58" } }, { "kind": "variablePdaSeedNode", "name": "post", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "variablePdaSeedNode", "name": "user", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "variablePdaSeedNode", "name": "kind", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } ] }, { "kind": "pdaNode", "name": "subscription", "docs": [], "seeds": [ { "kind": "constantPdaSeedNode", "type": { "kind": "bytesTypeNode" }, "value": { "kind": "bytesValueNode", "data": "fnKB", "encoding": "base58" } }, { "kind": "variablePdaSeedNode", "name": "follower", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "variablePdaSeedNode", "name": "author", "docs": [], "type": { "kind": "publicKeyTypeNode" } } ] }, { "kind": "pdaNode", "name": "post", "docs": [], "seeds": [ { "kind": "constantPdaSeedNode", "type": { "kind": "bytesTypeNode" }, "value": { "kind": "bytesValueNode", "data": "3sh3oZ", "encoding": "base58" } }, { "kind": "variablePdaSeedNode", "name": "profile", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "variablePdaSeedNode", "name": "postId", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } } ] } ], "events": [], "errors": [] }, "additionalPrograms": [] } ================================================ FILE: packages/dynamic-client/test/programs/idls/circular-account-refs-idl.json ================================================ { "kind": "rootNode", "standard": "codama", "version": "1.3.7", "program": { "kind": "programNode", "name": "circularAccountRefs", "publicKey": "BkppVYrCXNAr7rt6FRVBJ6ZxfcMLkkWUomuebFVnNAAt", "version": "0.1.0", "origin": "custom", "docs": ["Test program for circular account reference detection"], "accounts": [], "instructions": [ { "kind": "instructionNode", "name": "twoAccountCycle", "docs": ["Test A->B->A circular reference"], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "accountA", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "accountValueNode", "name": "accountB" } }, { "kind": "instructionAccountNode", "name": "accountB", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "accountValueNode", "name": "accountA" } } ], "arguments": [], "discriminators": [] }, { "kind": "instructionNode", "name": "selfReference", "docs": ["Test A->A self-reference cycle"], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "accountA", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "accountValueNode", "name": "accountA" } } ], "arguments": [], "discriminators": [] }, { "kind": "instructionNode", "name": "threeAccountCycle", "docs": ["Test A->B->C->A circular reference"], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "accountA", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "accountValueNode", "name": "accountB" } }, { "kind": "instructionAccountNode", "name": "accountB", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "accountValueNode", "name": "accountC" } }, { "kind": "instructionAccountNode", "name": "accountC", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "accountValueNode", "name": "accountA" } } ], "arguments": [], "discriminators": [] } ], "definedTypes": [], "pdas": [] }, "additionalPrograms": [] } ================================================ FILE: packages/dynamic-client/test/programs/idls/collection-types-idl.json ================================================ { "kind": "rootNode", "standard": "codama", "version": "1.5.1", "program": { "kind": "programNode", "name": "collectionTypes", "publicKey": "5YYZqJa7jR51426rhWhydoZJC3GSTtYDQNzJJrZqWxA4", "version": "0.1.0", "docs": [], "accounts": [], "instructions": [ { "kind": "instructionNode", "name": "storeTuple", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "signer", "isWritable": false, "isSigner": true, "isOptional": false, "docs": [] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 0 } }, { "kind": "instructionArgumentNode", "name": "data", "docs": [], "type": { "kind": "tupleTypeNode", "items": [ { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, { "kind": "sizePrefixTypeNode", "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" }, "type": { "kind": "stringTypeNode", "encoding": "utf8" } } ] } } ] }, { "kind": "instructionNode", "name": "storeMap", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "signer", "isWritable": false, "isSigner": true, "isOptional": false, "docs": [] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } }, { "kind": "instructionArgumentNode", "name": "data", "docs": [], "type": { "kind": "mapTypeNode", "key": { "kind": "sizePrefixTypeNode", "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" }, "type": { "kind": "stringTypeNode", "encoding": "utf8" } }, "value": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "count": { "kind": "prefixedCountNode", "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } } } ] }, { "kind": "instructionNode", "name": "storeSet", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "signer", "isWritable": false, "isSigner": true, "isOptional": false, "docs": [] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 2 } }, { "kind": "instructionArgumentNode", "name": "data", "docs": [], "type": { "kind": "setTypeNode", "item": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "count": { "kind": "prefixedCountNode", "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } } } ] }, { "kind": "instructionNode", "name": "storeNestedTuple", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "signer", "isWritable": false, "isSigner": true, "isOptional": false, "docs": [] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 6 } }, { "kind": "instructionArgumentNode", "name": "data", "docs": [], "type": { "kind": "tupleTypeNode", "items": [ { "kind": "mapTypeNode", "key": { "kind": "sizePrefixTypeNode", "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" }, "type": { "kind": "stringTypeNode", "encoding": "utf8" } }, "value": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "count": { "kind": "prefixedCountNode", "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "arrayTypeNode", "item": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "count": { "kind": "prefixedCountNode", "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } } ] } } ] }, { "kind": "instructionNode", "name": "storeNestedMap", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "signer", "isWritable": false, "isSigner": true, "isOptional": false, "docs": [] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 7 } }, { "kind": "instructionArgumentNode", "name": "data", "docs": [], "type": { "kind": "mapTypeNode", "key": { "kind": "sizePrefixTypeNode", "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" }, "type": { "kind": "stringTypeNode", "encoding": "utf8" } }, "value": { "kind": "arrayTypeNode", "item": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "count": { "kind": "prefixedCountNode", "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, "count": { "kind": "prefixedCountNode", "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } } } ] }, { "kind": "instructionNode", "name": "storeNestedSet", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "signer", "isWritable": false, "isSigner": true, "isOptional": false, "docs": [] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 8 } }, { "kind": "instructionArgumentNode", "name": "data", "docs": [], "type": { "kind": "setTypeNode", "item": { "kind": "tupleTypeNode", "items": [ { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, { "kind": "sizePrefixTypeNode", "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" }, "type": { "kind": "stringTypeNode", "encoding": "utf8" } } ] }, "count": { "kind": "prefixedCountNode", "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } } } ] } ], "definedTypes": [], "pdas": [], "errors": [] }, "additionalPrograms": [] } ================================================ FILE: packages/dynamic-client/test/programs/idls/custom-resolvers-test-idl.json ================================================ { "kind": "rootNode", "standard": "codama", "version": "1.5.1", "program": { "kind": "programNode", "name": "customResolversTest", "publicKey": "9oHr11Q3pmPsAkFNzQS3JjK5RJA9hwvwrSgF2MXvs22C", "version": "0.1.0", "docs": [ "Manually generated IDL for testing custom resolvers: argument resolvers, direct account resolvers, and conditional account resolvers." ], "pdas": [], "accounts": [], "definedTypes": [], "errors": [], "instructions": [ { "kind": "instructionNode", "name": "createItem", "docs": [], "accounts": [ { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 8 }, "defaultValueStrategy": "omitted" }, { "kind": "instructionArgumentNode", "name": "name", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "instructionArgumentNode", "name": "description", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "resolverValueNode", "name": "resolveDescription", "docs": [], "dependsOn": [] } }, { "kind": "instructionArgumentNode", "name": "tags", "docs": [], "defaultValueStrategy": "optional", "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "resolverValueNode", "name": "resolveTags", "docs": [], "dependsOn": [] } } ] }, { "kind": "instructionNode", "name": "transferWithResolver", "docs": ["Tests direct account resolverValueNode (Pattern 3)"], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "destination", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "resolverValueNode", "name": "resolveDestination", "docs": [], "dependsOn": [] } }, { "kind": "instructionAccountNode", "name": "treasury", "isWritable": false, "isSigner": false, "isOptional": true, "docs": [], "defaultValue": { "kind": "resolverValueNode", "name": "resolveTreasury", "docs": [], "dependsOn": [] } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 }, "defaultValueStrategy": "omitted" }, { "kind": "instructionArgumentNode", "name": "amount", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } } ] }, { "kind": "instructionNode", "name": "conditionalTransfer", "docs": ["Tests conditional resolver edge cases"], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "optionalTarget", "isWritable": false, "isSigner": false, "isOptional": true, "docs": [], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIncludeTarget", "docs": [], "dependsOn": [] }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111" } } }, { "kind": "instructionAccountNode", "name": "requiredTarget", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIncludeRequired", "docs": [], "dependsOn": [] }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111" } } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 2 }, "defaultValueStrategy": "omitted" } ] } ] }, "additionalPrograms": [] } ================================================ FILE: packages/dynamic-client/test/programs/idls/example-idl.json ================================================ { "kind": "rootNode", "standard": "codama", "version": "1.5.1", "program": { "kind": "programNode", "name": "example", "publicKey": "5xjPsgMHuoj4MrAPJVBrTomk5UAZvCxVtAdcWwgheoZs", "version": "0.1.0", "origin": "anchor", "docs": [], "accounts": [ { "kind": "accountNode", "name": "dataAccount1", "docs": [], "data": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "fixedSizeTypeNode", "size": 8, "type": { "kind": "bytesTypeNode" } }, "defaultValue": { "kind": "bytesValueNode", "data": "bd16d2a9c3062624", "encoding": "base16" } }, { "kind": "structFieldTypeNode", "name": "input", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "optionalInput", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "publicKeyTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "bump", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } ] }, "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "accountNode", "name": "nestedExampleAccount", "docs": [], "data": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "fixedSizeTypeNode", "size": 8, "type": { "kind": "bytesTypeNode" } }, "defaultValue": { "kind": "bytesValueNode", "data": "199431fafbc64cb8", "encoding": "base16" } }, { "kind": "structFieldTypeNode", "name": "input", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "structAndEnumsInput" } } ] }, "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "accountNode", "name": "storeOptionalAccount", "docs": [], "data": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "fixedSizeTypeNode", "size": 8, "type": { "kind": "bytesTypeNode" } }, "defaultValue": { "kind": "bytesValueNode", "data": "cdc23432ff1ff097", "encoding": "base16" } }, { "kind": "structFieldTypeNode", "name": "optionalAcc", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "publicKeyTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } } ] }, "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] } ], "instructions": [ { "kind": "instructionNode", "name": "externalProgramsWithPda", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "signer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "tokenAccount", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaNode", "name": "tokenAccount", "docs": [], "programId": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", "seeds": [ { "kind": "variablePdaSeedNode", "name": "signer", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "constantPdaSeedNode", "type": { "kind": "bytesTypeNode" }, "value": { "kind": "bytesValueNode", "data": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "encoding": "base58" } }, { "kind": "variablePdaSeedNode", "name": "mint", "docs": [], "type": { "kind": "publicKeyTypeNode" } } ] }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "signer", "value": { "kind": "accountValueNode", "name": "signer" } }, { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "dependentAccount", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "dependentAccount" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "signer", "value": { "kind": "accountValueNode", "name": "signer" } }, { "kind": "pdaSeedValueNode", "name": "tokenAccount", "value": { "kind": "accountValueNode", "name": "tokenAccount" } } ] } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "systemProgram" } }, { "kind": "instructionAccountNode", "name": "tokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "tokenProgram" } }, { "kind": "instructionAccountNode", "name": "associatedTokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", "identifier": "associatedTokenProgram" } }, { "kind": "instructionAccountNode", "name": "rent", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "SysvarRent111111111111111111111111111111111", "identifier": "rent" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "fixedSizeTypeNode", "size": 8, "type": { "kind": "bytesTypeNode" } }, "defaultValue": { "kind": "bytesValueNode", "data": "2d1ba417d532503f", "encoding": "base16" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "fourLevelPda", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "signer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "level1", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "level1" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "signer", "value": { "kind": "accountValueNode", "name": "signer" } } ] } }, { "kind": "instructionAccountNode", "name": "level2", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "level2" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "level1", "value": { "kind": "accountValueNode", "name": "level1" } } ] } }, { "kind": "instructionAccountNode", "name": "level3", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "level3" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "level2", "value": { "kind": "accountValueNode", "name": "level2" } } ] } }, { "kind": "instructionAccountNode", "name": "level4", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "level4" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "level3", "value": { "kind": "accountValueNode", "name": "level3" } } ] } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "systemProgram" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "fixedSizeTypeNode", "size": 8, "type": { "kind": "bytesTypeNode" } }, "defaultValue": { "kind": "bytesValueNode", "data": "0a91d0f7e05f68d9", "encoding": "base16" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "nestedExample", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "signer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "nestedExampleAccount", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "systemProgram" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "fixedSizeTypeNode", "size": 8, "type": { "kind": "bytesTypeNode" } }, "defaultValue": { "kind": "bytesValueNode", "data": "74d1961627e33e2f", "encoding": "base16" } }, { "kind": "instructionArgumentNode", "name": "input", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "structAndEnumsInput" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "noArguments", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "signer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "acc", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "systemProgram" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "fixedSizeTypeNode", "size": 8, "type": { "kind": "bytesTypeNode" } }, "defaultValue": { "kind": "bytesValueNode", "data": "d8babc37a02f97b1", "encoding": "base16" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "pubkeySeedIx", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "signer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "newAccount", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "newAccount" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "signer", "value": { "kind": "accountValueNode", "name": "signer" } } ] } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "systemProgram" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "fixedSizeTypeNode", "size": 8, "type": { "kind": "bytesTypeNode" } }, "defaultValue": { "kind": "bytesValueNode", "data": "fbe4907a8392e6e1", "encoding": "base16" } }, { "kind": "instructionArgumentNode", "name": "input", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "selfReferencePda", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "signer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "recursive", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "recursive" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "recursive", "value": { "kind": "accountValueNode", "name": "recursive" } } ] } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "systemProgram" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "fixedSizeTypeNode", "size": 8, "type": { "kind": "bytesTypeNode" } }, "defaultValue": { "kind": "bytesValueNode", "data": "5b16377c88fe854e", "encoding": "base16" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "stringSeedPda", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "signer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "pdaAccount", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "pdaAccount" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "id", "value": { "kind": "argumentValueNode", "name": "id" } }, { "kind": "pdaSeedValueNode", "name": "name", "value": { "kind": "argumentValueNode", "name": "name" } } ] } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "systemProgram" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "fixedSizeTypeNode", "size": 8, "type": { "kind": "bytesTypeNode" } }, "defaultValue": { "kind": "bytesValueNode", "data": "be1f479d57a0852b", "encoding": "base16" } }, { "kind": "instructionArgumentNode", "name": "name", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "instructionArgumentNode", "name": "id", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "twoNodeCyclePda", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "signer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "pdaA", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "pdaA" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "pdaB", "value": { "kind": "accountValueNode", "name": "pdaB" } } ] } }, { "kind": "instructionAccountNode", "name": "pdaB", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "pdaB" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "pdaA", "value": { "kind": "accountValueNode", "name": "pdaA" } } ] } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "systemProgram" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "fixedSizeTypeNode", "size": 8, "type": { "kind": "bytesTypeNode" } }, "defaultValue": { "kind": "bytesValueNode", "data": "a0c0bcc91ff667be", "encoding": "base16" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "updateOptionalAccount", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "signer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "createdOptionalAcc", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "createdOptionalAcc" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "id", "value": { "kind": "argumentValueNode", "name": "id" } } ] } }, { "kind": "instructionAccountNode", "name": "optionalAccKey", "isWritable": false, "isSigner": false, "isOptional": true, "docs": [] }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "systemProgram" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "fixedSizeTypeNode", "size": 8, "type": { "kind": "bytesTypeNode" } }, "defaultValue": { "kind": "bytesValueNode", "data": "f2c55828eba2993c", "encoding": "base16" } }, { "kind": "instructionArgumentNode", "name": "id", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "updateOptionalInput", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "signer", "isWritable": false, "isSigner": true, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "existingAccount", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "newAccount" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "signer", "value": { "kind": "accountValueNode", "name": "signer" } } ] } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "fixedSizeTypeNode", "size": 8, "type": { "kind": "bytesTypeNode" } }, "defaultValue": { "kind": "bytesValueNode", "data": "1f094566b31b79c7", "encoding": "base16" } }, { "kind": "instructionArgumentNode", "name": "input", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, { "kind": "instructionArgumentNode", "name": "optionalInput", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "publicKeyTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] } ], "definedTypes": [ { "kind": "definedTypeNode", "name": "command", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumTupleVariantTypeNode", "name": "start", "tuple": { "kind": "tupleTypeNode", "items": [ { "kind": "numberTypeNode", "format": "u64", "endian": "le" } ] } }, { "kind": "enumEmptyVariantTypeNode", "name": "stop" }, { "kind": "enumStructVariantTypeNode", "name": "continue", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "reason", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } } ] } } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "innerEnum", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumStructVariantTypeNode", "name": "tokenTransfer", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "amount", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "tokenType", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenType" } } ] } }, { "kind": "enumStructVariantTypeNode", "name": "stake", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "duration", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } } ] } }, { "kind": "enumEmptyVariantTypeNode", "name": "none" } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "innerHeader", "docs": [], "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "version", "docs": [], "type": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "command", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "command" } } ] } }, { "kind": "definedTypeNode", "name": "innerStruct", "docs": [], "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "value", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "name", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "seedEnum", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "seedEnum" } }, { "kind": "structFieldTypeNode", "name": "bytes", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "bytesTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "optionalPubkey", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "publicKeyTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "enumsArray", "docs": [], "type": { "kind": "arrayTypeNode", "item": { "kind": "definedTypeLinkNode", "name": "seedEnum" }, "count": { "kind": "fixedCountNode", "value": 2 } } } ] } }, { "kind": "definedTypeNode", "name": "seedEnum", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumEmptyVariantTypeNode", "name": "arm" }, { "kind": "enumEmptyVariantTypeNode", "name": "bar" }, { "kind": "enumEmptyVariantTypeNode", "name": "car" } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "structAndEnumsInput", "docs": [], "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "header", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "innerHeader" } }, { "kind": "structFieldTypeNode", "name": "innerStruct", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "innerStruct" } }, { "kind": "structFieldTypeNode", "name": "innerEnum", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "innerEnum" } }, { "kind": "structFieldTypeNode", "name": "seedEnum", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "seedEnum" } }, { "kind": "structFieldTypeNode", "name": "pubkey", "docs": [], "type": { "kind": "publicKeyTypeNode" } } ] } }, { "kind": "definedTypeNode", "name": "tokenType", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumEmptyVariantTypeNode", "name": "sPL" }, { "kind": "enumStructVariantTypeNode", "name": "nFT", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "collection", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } } ] } } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } } ], "pdas": [ { "kind": "pdaNode", "name": "dependentAccount", "docs": [], "seeds": [ { "kind": "constantPdaSeedNode", "type": { "kind": "bytesTypeNode" }, "value": { "kind": "bytesValueNode", "data": "jRu685RUxyrTMFKUptY", "encoding": "base58" } }, { "kind": "variablePdaSeedNode", "name": "signer", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "variablePdaSeedNode", "name": "tokenAccount", "docs": [], "type": { "kind": "publicKeyTypeNode" } } ] }, { "kind": "pdaNode", "name": "level1", "docs": [], "seeds": [ { "kind": "constantPdaSeedNode", "type": { "kind": "bytesTypeNode" }, "value": { "kind": "bytesValueNode", "data": "vyjhaZZA", "encoding": "base58" } }, { "kind": "variablePdaSeedNode", "name": "signer", "docs": [], "type": { "kind": "publicKeyTypeNode" } } ] }, { "kind": "pdaNode", "name": "level2", "docs": [], "seeds": [ { "kind": "constantPdaSeedNode", "type": { "kind": "bytesTypeNode" }, "value": { "kind": "bytesValueNode", "data": "vyjhaZZB", "encoding": "base58" } }, { "kind": "variablePdaSeedNode", "name": "level1", "docs": [], "type": { "kind": "publicKeyTypeNode" } } ] }, { "kind": "pdaNode", "name": "level3", "docs": [], "seeds": [ { "kind": "constantPdaSeedNode", "type": { "kind": "bytesTypeNode" }, "value": { "kind": "bytesValueNode", "data": "vyjhaZZC", "encoding": "base58" } }, { "kind": "variablePdaSeedNode", "name": "level2", "docs": [], "type": { "kind": "publicKeyTypeNode" } } ] }, { "kind": "pdaNode", "name": "level4", "docs": [], "seeds": [ { "kind": "constantPdaSeedNode", "type": { "kind": "bytesTypeNode" }, "value": { "kind": "bytesValueNode", "data": "vyjhaZZD", "encoding": "base58" } }, { "kind": "variablePdaSeedNode", "name": "level3", "docs": [], "type": { "kind": "publicKeyTypeNode" } } ] }, { "kind": "pdaNode", "name": "newAccount", "docs": [], "seeds": [ { "kind": "constantPdaSeedNode", "type": { "kind": "bytesTypeNode" }, "value": { "kind": "bytesValueNode", "data": "3x5dmD", "encoding": "base58" } }, { "kind": "variablePdaSeedNode", "name": "signer", "docs": [], "type": { "kind": "publicKeyTypeNode" } } ] }, { "kind": "pdaNode", "name": "recursive", "docs": [], "seeds": [ { "kind": "constantPdaSeedNode", "type": { "kind": "bytesTypeNode" }, "value": { "kind": "bytesValueNode", "data": "2TTMxGdnk9y5E", "encoding": "base58" } }, { "kind": "variablePdaSeedNode", "name": "recursive", "docs": [], "type": { "kind": "publicKeyTypeNode" } } ] }, { "kind": "pdaNode", "name": "pdaAccount", "docs": [], "seeds": [ { "kind": "variablePdaSeedNode", "name": "id", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, { "kind": "variablePdaSeedNode", "name": "name", "docs": [], "type": { "kind": "stringTypeNode", "encoding": "utf8" } } ] }, { "kind": "pdaNode", "name": "pdaA", "docs": [], "seeds": [ { "kind": "constantPdaSeedNode", "type": { "kind": "bytesTypeNode" }, "value": { "kind": "bytesValueNode", "data": "DgTMS8g", "encoding": "base58" } }, { "kind": "variablePdaSeedNode", "name": "pdaB", "docs": [], "type": { "kind": "publicKeyTypeNode" } } ] }, { "kind": "pdaNode", "name": "pdaB", "docs": [], "seeds": [ { "kind": "constantPdaSeedNode", "type": { "kind": "bytesTypeNode" }, "value": { "kind": "bytesValueNode", "data": "DgTMS8h", "encoding": "base58" } }, { "kind": "variablePdaSeedNode", "name": "pdaA", "docs": [], "type": { "kind": "publicKeyTypeNode" } } ] }, { "kind": "pdaNode", "name": "createdOptionalAcc", "docs": [], "seeds": [ { "kind": "constantPdaSeedNode", "type": { "kind": "bytesTypeNode" }, "value": { "kind": "bytesValueNode", "data": "36yLnDMJfhTHJWcBU", "encoding": "base58" } }, { "kind": "variablePdaSeedNode", "name": "id", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } } ] } ], "events": [], "errors": [] }, "additionalPrograms": [] } ================================================ FILE: packages/dynamic-client/test/programs/idls/mpl-token-metadata-idl.json ================================================ { "kind": "rootNode", "standard": "codama", "version": "1.5.0", "program": { "kind": "programNode", "name": "mplTokenMetadata", "publicKey": "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s", "version": "1.14.0", "origin": "shank", "docs": [], "accounts": [ { "kind": "accountNode", "name": "collectionAuthorityRecord", "docs": [], "data": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "key", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "key" }, "defaultValue": { "kind": "enumValueNode", "variant": "collectionAuthorityRecord", "enum": { "kind": "definedTypeLinkNode", "name": "key" } } }, { "kind": "structFieldTypeNode", "name": "bump", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "updateAuthority", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "publicKeyTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } } ] }, "pda": { "kind": "pdaLinkNode", "name": "collectionAuthorityRecord" }, "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "key", "offset": 0 } ] }, { "kind": "accountNode", "name": "metadataDelegateRecord", "size": 98, "docs": [], "data": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "key", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "key" } }, { "kind": "structFieldTypeNode", "name": "bump", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "mint", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "delegate", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "updateAuthority", "docs": [], "type": { "kind": "publicKeyTypeNode" } } ] }, "pda": { "kind": "pdaLinkNode", "name": "metadataDelegateRecord" } }, { "kind": "accountNode", "name": "holderDelegateRecord", "size": 98, "docs": [], "data": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "key", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "key" } }, { "kind": "structFieldTypeNode", "name": "bump", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "mint", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "delegate", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "updateAuthority", "docs": [], "type": { "kind": "publicKeyTypeNode" } } ] }, "pda": { "kind": "pdaLinkNode", "name": "holderDelegateRecord" } }, { "kind": "accountNode", "name": "edition", "size": 41, "docs": [], "data": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "key", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "key" }, "defaultValue": { "kind": "enumValueNode", "variant": "editionV1", "enum": { "kind": "definedTypeLinkNode", "name": "key" } } }, { "kind": "structFieldTypeNode", "name": "parent", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "edition", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } } ] }, "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "key", "offset": 0 } ] }, { "kind": "accountNode", "name": "editionMarker", "size": 32, "docs": [], "data": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "key", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "key" }, "defaultValue": { "kind": "enumValueNode", "variant": "editionMarker", "enum": { "kind": "definedTypeLinkNode", "name": "key" } } }, { "kind": "structFieldTypeNode", "name": "ledger", "docs": [], "type": { "kind": "fixedSizeTypeNode", "size": 31, "type": { "kind": "bytesTypeNode" } } } ] }, "pda": { "kind": "pdaLinkNode", "name": "editionMarker" }, "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "key", "offset": 0 } ] }, { "kind": "accountNode", "name": "editionMarkerV2", "docs": [], "data": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "key", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "key" } }, { "kind": "structFieldTypeNode", "name": "ledger", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "bytesTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } } ] }, "pda": { "kind": "pdaLinkNode", "name": "editionMarkerV2" } }, { "kind": "accountNode", "name": "tokenOwnedEscrow", "docs": [], "data": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "key", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "key" }, "defaultValue": { "kind": "enumValueNode", "variant": "tokenOwnedEscrow", "enum": { "kind": "definedTypeLinkNode", "name": "key" } } }, { "kind": "structFieldTypeNode", "name": "baseToken", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "authority", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "escrowAuthority" } }, { "kind": "structFieldTypeNode", "name": "bump", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } ] }, "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "key", "offset": 0 } ] }, { "kind": "accountNode", "name": "masterEdition", "size": null, "docs": [], "data": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "key", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "key" }, "defaultValue": { "kind": "enumValueNode", "variant": "masterEditionV2", "enum": { "kind": "definedTypeLinkNode", "name": "key" } } }, { "kind": "structFieldTypeNode", "name": "supply", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "maxSupply", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } } ] }, "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "key", "offset": 0 } ] }, { "kind": "accountNode", "name": "deprecatedMasterEditionV1", "size": null, "docs": [], "data": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "key", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "key" }, "defaultValue": { "kind": "enumValueNode", "variant": "masterEditionV1", "enum": { "kind": "definedTypeLinkNode", "name": "key" } } }, { "kind": "structFieldTypeNode", "name": "supply", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "maxSupply", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "printingMint", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "oneTimePrintingAuthorizationMint", "docs": [], "type": { "kind": "publicKeyTypeNode" } } ] }, "pda": { "kind": "pdaLinkNode", "name": "deprecatedMasterEditionV1" }, "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "key", "offset": 0 } ] }, { "kind": "accountNode", "name": "metadata", "size": null, "docs": [], "data": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "key", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "key" }, "defaultValue": { "kind": "enumValueNode", "variant": "metadataV1", "enum": { "kind": "definedTypeLinkNode", "name": "key" } } }, { "kind": "structFieldTypeNode", "name": "updateAuthority", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "mint", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "name", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "symbol", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "uri", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "sellerFeeBasisPoints", "docs": [], "type": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "creators", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "arrayTypeNode", "item": { "kind": "definedTypeLinkNode", "name": "creator" }, "count": { "kind": "prefixedCountNode", "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "primarySaleHappened", "docs": [], "type": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "isMutable", "docs": [], "type": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "editionNonce", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "tokenStandard", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "tokenStandard" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "collection", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "collection" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "uses", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "uses" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "collectionDetails", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "collectionDetails" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "programmableConfig", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "programmableConfig" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } } ] }, "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "key", "offset": 0 } ] }, { "kind": "accountNode", "name": "tokenRecord", "size": 80, "docs": [], "data": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "key", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "key" }, "defaultValue": { "kind": "enumValueNode", "variant": "tokenRecord", "enum": { "kind": "definedTypeLinkNode", "name": "key" } } }, { "kind": "structFieldTypeNode", "name": "bump", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "state", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenState" } }, { "kind": "structFieldTypeNode", "name": "ruleSetRevision", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "delegate", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "publicKeyTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "delegateRole", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "tokenDelegateRole" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "lockedTransfer", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "publicKeyTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } } ] }, "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "key", "offset": 0 } ] }, { "kind": "accountNode", "name": "useAuthorityRecord", "size": 10, "docs": [], "data": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "key", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "key" }, "defaultValue": { "kind": "enumValueNode", "variant": "useAuthorityRecord", "enum": { "kind": "definedTypeLinkNode", "name": "key" } } }, { "kind": "structFieldTypeNode", "name": "allowedUses", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "bump", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } ] }, "pda": { "kind": "pdaLinkNode", "name": "useAuthorityRecord" }, "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "key", "offset": 0 } ] } ], "instructions": [ { "kind": "instructionNode", "name": "deprecatedMintNewEditionFromMasterEditionViaPrintingToken", "docs": [], "optionalAccountStrategy": "omitted", "accounts": [ { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["New Metadata key (pda of ['metadata', program id, mint id])"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "edition", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["New Edition V1 (pda of ['metadata', program id, mint id, 'edition'])"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [ "Master Record Edition V1 (pda of ['metadata', program id, master metadata mint id, 'edition'])" ], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Mint of new token - THIS WILL TRANSFER AUTHORITY AWAY FROM THIS KEY"] }, { "kind": "instructionAccountNode", "name": "mintAuthority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Mint authority of new mint"] }, { "kind": "instructionAccountNode", "name": "printingMint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Printing Mint of master record edition"] }, { "kind": "instructionAccountNode", "name": "masterTokenAccount", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token account containing Printing mint token to be transferred"] }, { "kind": "instructionAccountNode", "name": "editionMarker", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [ "Edition pda to mark creation - will be checked for pre-existence. (pda of ['metadata', program id, master mint id, edition_number])" ] }, { "kind": "instructionAccountNode", "name": "burnAuthority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Burn authority for this token"] }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "masterUpdateAuthority", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["update authority info for new metadata account"] }, { "kind": "instructionAccountNode", "name": "masterMetadata", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Master record metadata account"] }, { "kind": "instructionAccountNode", "name": "tokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Token program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "rent", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Rent info"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "SysvarRent111111111111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "reservationList", "isWritable": true, "isSigner": false, "isOptional": true, "docs": [ "Reservation List - If present, and you are on this list, you can get an edition number given by your position on the list." ] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 3 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "updatePrimarySaleHappenedViaToken", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata key (pda of ['metadata', program id, mint id])"] }, { "kind": "instructionAccountNode", "name": "owner", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Owner on the token account"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Account containing tokens from the metadata's mint"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 4 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "signMetadata", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata (pda of ['metadata', program id, mint id])"] }, { "kind": "instructionAccountNode", "name": "creator", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Creator"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 7 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "mintNewEditionFromMasterEditionViaToken", "docs": [], "optionalAccountStrategy": "omitted", "accounts": [ { "kind": "instructionAccountNode", "name": "newMetadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["New Metadata key (pda of ['metadata', program id, mint id])"] }, { "kind": "instructionAccountNode", "name": "newEdition", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["New Edition (pda of ['metadata', program id, mint id, 'edition'])"] }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [ "Master Record Edition V2 (pda of ['metadata', program id, master metadata mint id, 'edition'])" ] }, { "kind": "instructionAccountNode", "name": "newMint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Mint of new token - THIS WILL TRANSFER AUTHORITY AWAY FROM THIS KEY"] }, { "kind": "instructionAccountNode", "name": "editionMarkPda", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [ "Edition pda to mark creation - will be checked for pre-existence. (pda of ['metadata', program id, master metadata mint id, 'edition', edition_number]) where edition_number is NOT the edition number you pass in args but actually edition_number = floor(edition/EDITION_MARKER_BIT_SIZE)." ] }, { "kind": "instructionAccountNode", "name": "newMintAuthority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Mint authority of new mint"] }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "tokenAccountOwner", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["owner of token account containing master token (#8)"] }, { "kind": "instructionAccountNode", "name": "tokenAccount", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["token account containing token from master metadata mint"] }, { "kind": "instructionAccountNode", "name": "newMetadataUpdateAuthority", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Update authority info for new metadata"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Master record metadata account"] }, { "kind": "instructionAccountNode", "name": "tokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Token program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "rent", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Rent info"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 11 } }, { "kind": "instructionArgumentNode", "name": "mintNewEditionFromMasterEditionViaTokenArgs", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "mintNewEditionFromMasterEditionViaTokenArgs" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "convertMasterEditionV1ToV2", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [ "Master Record Edition V1 (pda of ['metadata', program id, master metadata mint id, 'edition'])" ] }, { "kind": "instructionAccountNode", "name": "oneTimeAuth", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["One time authorization mint"] }, { "kind": "instructionAccountNode", "name": "printingMint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Printing mint"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 12 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "mintNewEditionFromMasterEditionViaVaultProxy", "docs": [], "optionalAccountStrategy": "omitted", "accounts": [ { "kind": "instructionAccountNode", "name": "newMetadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["New Metadata key (pda of ['metadata', program id, mint id])"] }, { "kind": "instructionAccountNode", "name": "newEdition", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["New Edition (pda of ['metadata', program id, mint id, 'edition'])"] }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [ "Master Record Edition V2 (pda of ['metadata', program id, master metadata mint id, 'edition']" ] }, { "kind": "instructionAccountNode", "name": "newMint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Mint of new token - THIS WILL TRANSFER AUTHORITY AWAY FROM THIS KEY"] }, { "kind": "instructionAccountNode", "name": "editionMarkPda", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [ "Edition pda to mark creation - will be checked for pre-existence. (pda of ['metadata', program id, master metadata mint id, 'edition', edition_number]) where edition_number is NOT the edition number you pass in args but actually edition_number = floor(edition/EDITION_MARKER_BIT_SIZE)." ] }, { "kind": "instructionAccountNode", "name": "newMintAuthority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Mint authority of new mint"] }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "vaultAuthority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Vault authority"] }, { "kind": "instructionAccountNode", "name": "safetyDepositStore", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Safety deposit token store account"] }, { "kind": "instructionAccountNode", "name": "safetyDepositBox", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Safety deposit box"] }, { "kind": "instructionAccountNode", "name": "vault", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Vault"] }, { "kind": "instructionAccountNode", "name": "newMetadataUpdateAuthority", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Update authority info for new metadata"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Master record metadata account"] }, { "kind": "instructionAccountNode", "name": "tokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Token program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } }, { "kind": "instructionAccountNode", "name": "tokenVaultProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Token vault program"] }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "rent", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Rent info"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 13 } }, { "kind": "instructionArgumentNode", "name": "mintNewEditionFromMasterEditionViaTokenArgs", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "mintNewEditionFromMasterEditionViaTokenArgs" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "puffMetadata", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 14 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "updateMetadataAccountV2", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"] }, { "kind": "instructionAccountNode", "name": "updateAuthority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority key"], "defaultValue": { "kind": "identityValueNode" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 15 } }, { "kind": "instructionArgumentNode", "name": "data", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "dataV2" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "instructionArgumentNode", "name": "newUpdateAuthority", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "publicKeyTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "instructionArgumentNode", "name": "primarySaleHappened", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "instructionArgumentNode", "name": "isMutable", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "createMasterEditionV3", "docs": [], "optionalAccountStrategy": "omitted", "accounts": [ { "kind": "instructionAccountNode", "name": "edition", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [ "Unallocated edition V2 account with address as pda of ['metadata', program id, mint, 'edition']" ], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata mint"] }, { "kind": "instructionAccountNode", "name": "updateAuthority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority"], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "mintAuthority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": [ "Mint authority on the metadata's mint - THIS WILL TRANSFER AUTHORITY AWAY FROM THIS KEY" ] }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "tokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Token program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "rent", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Rent info"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 17 } }, { "kind": "instructionArgumentNode", "name": "maxSupply", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "verifyCollection", "docs": [], "optionalAccountStrategy": "omitted", "accounts": [ { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"] }, { "kind": "instructionAccountNode", "name": "collectionAuthority", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Collection Update authority"] }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "collectionMint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of the Collection"] }, { "kind": "instructionAccountNode", "name": "collection", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Metadata Account of the Collection"] }, { "kind": "instructionAccountNode", "name": "collectionMasterEditionAccount", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["MasterEdition2 Account of the Collection Token"] }, { "kind": "instructionAccountNode", "name": "collectionAuthorityRecord", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Collection Authority Record PDA"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 18 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "utilize", "docs": [], "optionalAccountStrategy": "omitted", "accounts": [ { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "tokenAccount", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token Account Of NFT"] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Mint of the Metadata"] }, { "kind": "instructionAccountNode", "name": "useAuthority", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["A Use Authority / Can be the current Owner of the NFT"] }, { "kind": "instructionAccountNode", "name": "owner", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Owner"] }, { "kind": "instructionAccountNode", "name": "tokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Token program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } }, { "kind": "instructionAccountNode", "name": "ataProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Associated Token program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", "identifier": "splAssociatedToken" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "rent", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Rent info"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "SysvarRent111111111111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "useAuthorityRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Use Authority Record PDA If present the program Assumes a delegated use authority"] }, { "kind": "instructionAccountNode", "name": "burner", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Program As Signer (Burner)"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 19 } }, { "kind": "instructionArgumentNode", "name": "numberOfUses", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "approveUseAuthority", "docs": [], "optionalAccountStrategy": "omitted", "accounts": [ { "kind": "instructionAccountNode", "name": "useAuthorityRecord", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Use Authority Record PDA"] }, { "kind": "instructionAccountNode", "name": "owner", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Owner"] }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "user", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["A Use Authority"] }, { "kind": "instructionAccountNode", "name": "ownerTokenAccount", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Owned Token Account Of Mint"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of Metadata"] }, { "kind": "instructionAccountNode", "name": "burner", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Program As Signer (Burner)"] }, { "kind": "instructionAccountNode", "name": "tokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Token program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "rent", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Rent info"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 20 } }, { "kind": "instructionArgumentNode", "name": "numberOfUses", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "revokeUseAuthority", "docs": [], "optionalAccountStrategy": "omitted", "accounts": [ { "kind": "instructionAccountNode", "name": "useAuthorityRecord", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Use Authority Record PDA"] }, { "kind": "instructionAccountNode", "name": "owner", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Owner"] }, { "kind": "instructionAccountNode", "name": "user", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["A Use Authority"] }, { "kind": "instructionAccountNode", "name": "ownerTokenAccount", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Owned Token Account Of Mint"] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of Metadata"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "tokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Token program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "rent", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Rent info"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 21 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "unverifyCollection", "docs": [], "optionalAccountStrategy": "omitted", "accounts": [ { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"] }, { "kind": "instructionAccountNode", "name": "collectionAuthority", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Collection Authority"] }, { "kind": "instructionAccountNode", "name": "collectionMint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of the Collection"] }, { "kind": "instructionAccountNode", "name": "collection", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Metadata Account of the Collection"] }, { "kind": "instructionAccountNode", "name": "collectionMasterEditionAccount", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["MasterEdition2 Account of the Collection Token"] }, { "kind": "instructionAccountNode", "name": "collectionAuthorityRecord", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Collection Authority Record PDA"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 22 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "approveCollectionAuthority", "docs": [], "optionalAccountStrategy": "omitted", "accounts": [ { "kind": "instructionAccountNode", "name": "collectionAuthorityRecord", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Collection Authority Record PDA"] }, { "kind": "instructionAccountNode", "name": "newCollectionAuthority", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["A Collection Authority"] }, { "kind": "instructionAccountNode", "name": "updateAuthority", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Update Authority of Collection NFT"], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Collection Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of Collection Metadata"] }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "rent", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Rent info"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 23 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "revokeCollectionAuthority", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "collectionAuthorityRecord", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Collection Authority Record PDA"] }, { "kind": "instructionAccountNode", "name": "delegateAuthority", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Delegated Collection Authority"] }, { "kind": "instructionAccountNode", "name": "revokeAuthority", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Update Authority, or Delegated Authority, of Collection NFT"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of Metadata"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 24 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "setAndVerifyCollection", "docs": [], "optionalAccountStrategy": "omitted", "accounts": [ { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"] }, { "kind": "instructionAccountNode", "name": "collectionAuthority", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Collection Update authority"] }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "updateAuthority", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Update Authority of Collection NFT and NFT"], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "collectionMint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of the Collection"] }, { "kind": "instructionAccountNode", "name": "collection", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Metadata Account of the Collection"] }, { "kind": "instructionAccountNode", "name": "collectionMasterEditionAccount", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["MasterEdition2 Account of the Collection Token"] }, { "kind": "instructionAccountNode", "name": "collectionAuthorityRecord", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Collection Authority Record PDA"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 25 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "freezeDelegatedAccount", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "delegate", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Delegate"] }, { "kind": "instructionAccountNode", "name": "tokenAccount", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token account to freeze"] }, { "kind": "instructionAccountNode", "name": "edition", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Edition"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Token mint"] }, { "kind": "instructionAccountNode", "name": "tokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Token Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 26 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "thawDelegatedAccount", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "delegate", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Delegate"] }, { "kind": "instructionAccountNode", "name": "tokenAccount", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token account to thaw"] }, { "kind": "instructionAccountNode", "name": "edition", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Edition"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Token mint"] }, { "kind": "instructionAccountNode", "name": "tokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Token Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 27 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "removeCreatorVerification", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata (pda of ['metadata', program id, mint id])"] }, { "kind": "instructionAccountNode", "name": "creator", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Creator"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 28 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "burnNft", "docs": [], "optionalAccountStrategy": "omitted", "accounts": [ { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata (pda of ['metadata', program id, mint id])"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "owner", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["NFT owner"] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Mint of the NFT"] }, { "kind": "instructionAccountNode", "name": "tokenAccount", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token account to close"] }, { "kind": "instructionAccountNode", "name": "masterEditionAccount", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["MasterEdition2 of the NFT"] }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["SPL Token Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } }, { "kind": "instructionAccountNode", "name": "collectionMetadata", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Metadata of the Collection"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 29 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "verifySizedCollectionItem", "docs": [], "optionalAccountStrategy": "omitted", "accounts": [ { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"] }, { "kind": "instructionAccountNode", "name": "collectionAuthority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Collection Update authority"] }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "collectionMint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of the Collection"] }, { "kind": "instructionAccountNode", "name": "collection", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata Account of the Collection"] }, { "kind": "instructionAccountNode", "name": "collectionMasterEditionAccount", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["MasterEdition2 Account of the Collection Token"] }, { "kind": "instructionAccountNode", "name": "collectionAuthorityRecord", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Collection Authority Record PDA"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 30 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "unverifySizedCollectionItem", "docs": [], "optionalAccountStrategy": "omitted", "accounts": [ { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"] }, { "kind": "instructionAccountNode", "name": "collectionAuthority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Collection Authority"] }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "collectionMint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of the Collection"] }, { "kind": "instructionAccountNode", "name": "collection", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata Account of the Collection"] }, { "kind": "instructionAccountNode", "name": "collectionMasterEditionAccount", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["MasterEdition2 Account of the Collection Token"] }, { "kind": "instructionAccountNode", "name": "collectionAuthorityRecord", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Collection Authority Record PDA"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 31 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "setAndVerifySizedCollectionItem", "docs": [], "optionalAccountStrategy": "omitted", "accounts": [ { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"] }, { "kind": "instructionAccountNode", "name": "collectionAuthority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Collection Update authority"] }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "updateAuthority", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Update Authority of Collection NFT and NFT"], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "collectionMint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of the Collection"] }, { "kind": "instructionAccountNode", "name": "collection", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata Account of the Collection"] }, { "kind": "instructionAccountNode", "name": "collectionMasterEditionAccount", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["MasterEdition2 Account of the Collection Token"] }, { "kind": "instructionAccountNode", "name": "collectionAuthorityRecord", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Collection Authority Record PDA"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 32 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "createMetadataAccountV3", "docs": [], "optionalAccountStrategy": "omitted", "accounts": [ { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata key (pda of ['metadata', program id, mint id])"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of token asset"] }, { "kind": "instructionAccountNode", "name": "mintAuthority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Mint authority"] }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "updateAuthority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["update authority info"], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "rent", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Rent info"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 33 } }, { "kind": "instructionArgumentNode", "name": "data", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "dataV2" } }, { "kind": "instructionArgumentNode", "name": "isMutable", "docs": [], "type": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "instructionArgumentNode", "name": "collectionDetails", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "collectionDetails" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "setCollectionSize", "docs": [], "optionalAccountStrategy": "omitted", "accounts": [ { "kind": "instructionAccountNode", "name": "collectionMetadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Collection Metadata account"] }, { "kind": "instructionAccountNode", "name": "collectionAuthority", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Collection Update authority"] }, { "kind": "instructionAccountNode", "name": "collectionMint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of the Collection"] }, { "kind": "instructionAccountNode", "name": "collectionAuthorityRecord", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Collection Authority Record PDA"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 34 } }, { "kind": "instructionArgumentNode", "name": "setCollectionSizeArgs", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "setCollectionSizeArgs" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "setTokenStandard", "docs": [], "optionalAccountStrategy": "omitted", "accounts": [ { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "updateAuthority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Metadata update authority"], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint account"] }, { "kind": "instructionAccountNode", "name": "edition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Edition account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 35 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "bubblegumSetCollectionSize", "docs": [], "optionalAccountStrategy": "omitted", "accounts": [ { "kind": "instructionAccountNode", "name": "collectionMetadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Collection Metadata account"] }, { "kind": "instructionAccountNode", "name": "collectionAuthority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Collection Update authority"] }, { "kind": "instructionAccountNode", "name": "collectionMint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of the Collection"] }, { "kind": "instructionAccountNode", "name": "bubblegumSigner", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Signing PDA of Bubblegum program"] }, { "kind": "instructionAccountNode", "name": "collectionAuthorityRecord", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Collection Authority Record PDA"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 36 } }, { "kind": "instructionArgumentNode", "name": "setCollectionSizeArgs", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "setCollectionSizeArgs" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "burnEditionNft", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata (pda of ['metadata', program id, mint id])"] }, { "kind": "instructionAccountNode", "name": "owner", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["NFT owner"] }, { "kind": "instructionAccountNode", "name": "printEditionMint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Mint of the print edition NFT"] }, { "kind": "instructionAccountNode", "name": "masterEditionMint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of the original/master NFT"] }, { "kind": "instructionAccountNode", "name": "printEditionTokenAccount", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token account the print edition NFT is in"] }, { "kind": "instructionAccountNode", "name": "masterEditionTokenAccount", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Token account the Master Edition NFT is in"] }, { "kind": "instructionAccountNode", "name": "masterEditionAccount", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["MasterEdition2 of the original NFT"] }, { "kind": "instructionAccountNode", "name": "printEditionAccount", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Print Edition account of the NFT"] }, { "kind": "instructionAccountNode", "name": "editionMarkerAccount", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Edition Marker PDA of the NFT"] }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["SPL Token Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 37 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "createEscrowAccount", "docs": [], "optionalAccountStrategy": "omitted", "accounts": [ { "kind": "instructionAccountNode", "name": "escrow", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Escrow account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint account"] }, { "kind": "instructionAccountNode", "name": "tokenAccount", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Token account of the token"] }, { "kind": "instructionAccountNode", "name": "edition", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Edition account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Wallet paying for the transaction and new account"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": true, "docs": ["Authority/creator of the escrow account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 38 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "closeEscrowAccount", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "escrow", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Escrow account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint account"] }, { "kind": "instructionAccountNode", "name": "tokenAccount", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Token account"] }, { "kind": "instructionAccountNode", "name": "edition", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Edition account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Wallet paying for the transaction and new account"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 39 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "transferOutOfEscrow", "docs": [], "optionalAccountStrategy": "omitted", "accounts": [ { "kind": "instructionAccountNode", "name": "escrow", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Escrow account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"] }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Wallet paying for the transaction and new account"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "attributeMint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint account for the new attribute"] }, { "kind": "instructionAccountNode", "name": "attributeSrc", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token account source for the new attribute"] }, { "kind": "instructionAccountNode", "name": "attributeDst", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token account, owned by TM, destination for the new attribute"] }, { "kind": "instructionAccountNode", "name": "escrowMint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint account that the escrow is attached"] }, { "kind": "instructionAccountNode", "name": "escrowAccount", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Token account that holds the token the escrow is attached to"] }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "ataProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Associated Token program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", "identifier": "splAssociatedToken" } }, { "kind": "instructionAccountNode", "name": "tokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Token program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": true, "docs": ["Authority/creator of the escrow account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 40 } }, { "kind": "instructionArgumentNode", "name": "amount", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "burn", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "authority", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Asset owner or Utility delegate"], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "collectionMetadata", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Metadata of the Collection"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata (pda of ['metadata', program id, mint id])"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "edition", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Edition of the asset"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Mint of token asset"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token account to close"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "argumentValueNode", "name": "tokenOwner" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Master edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "masterEditionMint" }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "masterEditionMint" } } ] } } }, { "kind": "instructionAccountNode", "name": "masterEditionMint", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master edition mint of the asset"] }, { "kind": "instructionAccountNode", "name": "masterEditionToken", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master edition token account"] }, { "kind": "instructionAccountNode", "name": "editionMarker", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Edition marker account"] }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "argumentValueNode", "name": "tokenStandard" }, "value": { "kind": "enumValueNode", "variant": "programmableNonFungible", "enum": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "token" } } ] } } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["SPL Token Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 41 } }, { "kind": "instructionArgumentNode", "name": "burnArgs", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "burnArgs" } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenOwner", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "subInstructions": [ { "kind": "instructionNode", "name": "burnV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "authority", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Asset owner or Utility delegate"], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "collectionMetadata", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Metadata of the Collection"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata (pda of ['metadata', program id, mint id])"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "edition", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Edition of the asset"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Mint of token asset"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token account to close"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "argumentValueNode", "name": "tokenOwner" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Master edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "masterEditionMint" }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "masterEditionMint" } } ] } } }, { "kind": "instructionAccountNode", "name": "masterEditionMint", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master edition mint of the asset"] }, { "kind": "instructionAccountNode", "name": "masterEditionToken", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master edition token account"] }, { "kind": "instructionAccountNode", "name": "editionMarker", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Edition marker account"] }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "argumentValueNode", "name": "tokenStandard" }, "value": { "kind": "enumValueNode", "variant": "programmableNonFungible", "enum": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "token" } } ] } } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["SPL Token Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 41 } }, { "kind": "instructionArgumentNode", "name": "burnV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 0 } }, { "kind": "instructionArgumentNode", "name": "amount", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenOwner", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] } ] }, { "kind": "instructionNode", "name": "create", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [ "Unallocated metadata account with address as pda of ['metadata', program id, mint id]" ], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": true, "isSigner": false, "isOptional": true, "docs": [ "Unallocated edition account with address as pda of ['metadata', program id, mint, 'edition']" ] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": "either", "isOptional": false, "docs": ["Mint of token asset"] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Mint authority"], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "updateAuthority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["Update authority for the metadata account"], "defaultValue": { "kind": "accountValueNode", "name": "authority" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["SPL Token program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungibleOrIsMintSigner", "docs": [], "dependsOn": [ { "kind": "accountValueNode", "name": "mint" }, { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 42 } }, { "kind": "instructionArgumentNode", "name": "createArgs", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "createArgs" } } ], "byteDeltas": [ { "kind": "instructionByteDeltaNode", "withHeader": false, "value": { "kind": "numberValueNode", "number": 1427 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "subInstructions": [ { "kind": "instructionNode", "name": "createV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [ "Unallocated metadata account with address as pda of ['metadata', program id, mint id]" ], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": true, "isSigner": false, "isOptional": true, "docs": [ "Unallocated edition account with address as pda of ['metadata', program id, mint, 'edition']" ], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": "either", "isOptional": false, "docs": ["Mint of token asset"] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Mint authority"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "updateAuthority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["Update authority for the metadata account"], "defaultValue": { "kind": "accountValueNode", "name": "authority" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["SPL Token program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungibleOrIsMintSigner", "docs": [], "dependsOn": [ { "kind": "accountValueNode", "name": "mint" }, { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 42 } }, { "kind": "instructionArgumentNode", "name": "createV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 0 } }, { "kind": "instructionArgumentNode", "name": "name", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "instructionArgumentNode", "name": "symbol", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } }, "defaultValue": { "kind": "stringValueNode", "string": "" } }, { "kind": "instructionArgumentNode", "name": "uri", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "instructionArgumentNode", "name": "sellerFeeBasisPoints", "docs": [], "type": { "kind": "amountTypeNode", "decimals": 2, "unit": "%", "number": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } } }, { "kind": "instructionArgumentNode", "name": "creators", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "arrayTypeNode", "item": { "kind": "definedTypeLinkNode", "name": "creator" }, "count": { "kind": "prefixedCountNode", "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "resolverValueNode", "name": "resolveCreators", "docs": [], "dependsOn": [ { "kind": "accountValueNode", "name": "authority" } ] } }, { "kind": "instructionArgumentNode", "name": "primarySaleHappened", "docs": [], "type": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "booleanValueNode", "boolean": false } }, { "kind": "instructionArgumentNode", "name": "isMutable", "docs": [], "type": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "booleanValueNode", "boolean": true } }, { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" }, "defaultValue": { "kind": "enumValueNode", "variant": "nonFungible", "enum": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } } }, { "kind": "instructionArgumentNode", "name": "collection", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "collection" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "instructionArgumentNode", "name": "uses", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "uses" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "instructionArgumentNode", "name": "collectionDetails", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "collectionDetails" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "resolverValueNode", "name": "resolveCollectionDetails", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "isCollection" } ] } }, { "kind": "instructionArgumentNode", "name": "ruleSet", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "publicKeyTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "instructionArgumentNode", "name": "decimals", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "resolverValueNode", "name": "resolveDecimals", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] } }, { "kind": "instructionArgumentNode", "name": "printSupply", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "printSupply" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "resolverValueNode", "name": "resolvePrintSupply", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "isCollection", "docs": [], "type": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "booleanValueNode", "boolean": false } } ], "byteDeltas": [ { "kind": "instructionByteDeltaNode", "withHeader": false, "value": { "kind": "resolverValueNode", "name": "resolveCreateV1Bytes", "docs": [] } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] } ] }, { "kind": "instructionNode", "name": "mint", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token or Associated Token account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "accountValueNode", "name": "tokenOwner" } } ] } }, { "kind": "instructionAccountNode", "name": "tokenOwner", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Owner of the token account"], "defaultValue": { "kind": "resolverValueNode", "name": "resolveOptionalTokenOwner", "docs": [] } }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Metadata account (pda of ['metadata', program id, mint id])"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Master Edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "argumentValueNode", "name": "tokenStandard" }, "value": { "kind": "enumValueNode", "variant": "programmableNonFungible", "enum": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "token" } } ] } } }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Mint of token asset"] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["(Mint or Update) authority"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Metadata delegate record"] }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["SPL Token program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } }, { "kind": "instructionAccountNode", "name": "splAtaProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["SPL Associated Token Account program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", "identifier": "splAssociatedToken" } }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 43 } }, { "kind": "instructionArgumentNode", "name": "mintArgs", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "mintArgs" } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } } ], "byteDeltas": [ { "kind": "instructionByteDeltaNode", "withHeader": false, "value": { "kind": "numberValueNode", "number": 468 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "subInstructions": [ { "kind": "instructionNode", "name": "mintV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token or Associated Token account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "accountValueNode", "name": "tokenOwner" } } ] } }, { "kind": "instructionAccountNode", "name": "tokenOwner", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Owner of the token account"], "defaultValue": { "kind": "resolverValueNode", "name": "resolveOptionalTokenOwner", "docs": [] } }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Metadata account (pda of ['metadata', program id, mint id])"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Master Edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "argumentValueNode", "name": "tokenStandard" }, "value": { "kind": "enumValueNode", "variant": "programmableNonFungible", "enum": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "token" } } ] } } }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Mint of token asset"] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["(Mint or Update) authority"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Metadata delegate record"] }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["SPL Token program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } }, { "kind": "instructionAccountNode", "name": "splAtaProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["SPL Associated Token Account program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", "identifier": "splAssociatedToken" } }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 43 } }, { "kind": "instructionArgumentNode", "name": "mintV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 0 } }, { "kind": "instructionArgumentNode", "name": "amount", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } }, { "kind": "instructionArgumentNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } } ], "byteDeltas": [ { "kind": "instructionByteDeltaNode", "withHeader": false, "value": { "kind": "numberValueNode", "number": 468 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] } ] }, { "kind": "instructionNode", "name": "delegate", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Delegate record account"] }, { "kind": "instructionAccountNode", "name": "delegate", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Owner of the delegated account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master Edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of metadata"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token account of mint"] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or token owner"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["SPL Token Program"] }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 44 } }, { "kind": "instructionArgumentNode", "name": "delegateArgs", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "delegateArgs" } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "subInstructions": [ { "kind": "instructionNode", "name": "delegateCollectionV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Delegate record account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadataDelegateRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "delegateRole", "value": { "kind": "enumValueNode", "variant": "collection", "enum": { "kind": "definedTypeLinkNode", "name": "metadataDelegateRole" } } }, { "kind": "pdaSeedValueNode", "name": "updateAuthority", "value": { "kind": "argumentValueNode", "name": "updateAuthority" } }, { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "delegate", "value": { "kind": "accountValueNode", "name": "delegate" } } ] } }, { "kind": "instructionAccountNode", "name": "delegate", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Owner of the delegated account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master Edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of metadata"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token account of mint"] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or token owner"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["SPL Token Program"] }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 44 } }, { "kind": "instructionArgumentNode", "name": "delegateCollectionV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 0 } }, { "kind": "instructionArgumentNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, { "kind": "instructionArgumentNode", "name": "updateAuthority", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "accountValueNode", "name": "authority" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "delegateSaleV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Delegate record account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "token" } } ] } }, { "kind": "instructionAccountNode", "name": "delegate", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Owner of the delegated account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master Edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "argumentValueNode", "name": "tokenStandard" }, "value": { "kind": "enumValueNode", "variant": "programmableNonFungible", "enum": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "token" } } ] } } }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of metadata"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token account of mint"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "argumentValueNode", "name": "tokenOwner" } } ] } }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or token owner"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["SPL Token Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 44 } }, { "kind": "instructionArgumentNode", "name": "delegateSaleV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } }, { "kind": "instructionArgumentNode", "name": "amount", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } }, { "kind": "instructionArgumentNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, { "kind": "instructionArgumentNode", "name": "tokenOwner", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "identityValueNode" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "delegateTransferV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Delegate record account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "token" } } ] } }, { "kind": "instructionAccountNode", "name": "delegate", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Owner of the delegated account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master Edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "argumentValueNode", "name": "tokenStandard" }, "value": { "kind": "enumValueNode", "variant": "programmableNonFungible", "enum": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "token" } } ] } } }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of metadata"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token account of mint"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "argumentValueNode", "name": "tokenOwner" } } ] } }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or token owner"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["SPL Token Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 44 } }, { "kind": "instructionArgumentNode", "name": "delegateTransferV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 2 } }, { "kind": "instructionArgumentNode", "name": "amount", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } }, { "kind": "instructionArgumentNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, { "kind": "instructionArgumentNode", "name": "tokenOwner", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "identityValueNode" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "delegateDataV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Delegate record account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadataDelegateRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "delegateRole", "value": { "kind": "enumValueNode", "variant": "data", "enum": { "kind": "definedTypeLinkNode", "name": "metadataDelegateRole" } } }, { "kind": "pdaSeedValueNode", "name": "updateAuthority", "value": { "kind": "argumentValueNode", "name": "updateAuthority" } }, { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "delegate", "value": { "kind": "accountValueNode", "name": "delegate" } } ] } }, { "kind": "instructionAccountNode", "name": "delegate", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Owner of the delegated account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master Edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of metadata"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token account of mint"] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or token owner"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["SPL Token Program"] }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 44 } }, { "kind": "instructionArgumentNode", "name": "delegateDataV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 3 } }, { "kind": "instructionArgumentNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, { "kind": "instructionArgumentNode", "name": "updateAuthority", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "accountValueNode", "name": "authority" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "delegateUtilityV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Delegate record account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "token" } } ] } }, { "kind": "instructionAccountNode", "name": "delegate", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Owner of the delegated account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master Edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "argumentValueNode", "name": "tokenStandard" }, "value": { "kind": "enumValueNode", "variant": "programmableNonFungible", "enum": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "token" } } ] } } }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of metadata"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token account of mint"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "argumentValueNode", "name": "tokenOwner" } } ] } }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or token owner"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["SPL Token Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 44 } }, { "kind": "instructionArgumentNode", "name": "delegateUtilityV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 4 } }, { "kind": "instructionArgumentNode", "name": "amount", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } }, { "kind": "instructionArgumentNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, { "kind": "instructionArgumentNode", "name": "tokenOwner", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "identityValueNode" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "delegateStakingV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Delegate record account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "token" } } ] } }, { "kind": "instructionAccountNode", "name": "delegate", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Owner of the delegated account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master Edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "argumentValueNode", "name": "tokenStandard" }, "value": { "kind": "enumValueNode", "variant": "programmableNonFungible", "enum": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "token" } } ] } } }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of metadata"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token account of mint"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "argumentValueNode", "name": "tokenOwner" } } ] } }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or token owner"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["SPL Token Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 44 } }, { "kind": "instructionArgumentNode", "name": "delegateStakingV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 5 } }, { "kind": "instructionArgumentNode", "name": "amount", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } }, { "kind": "instructionArgumentNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, { "kind": "instructionArgumentNode", "name": "tokenOwner", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "identityValueNode" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "delegateStandardV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Delegate record account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "token" } } ] } }, { "kind": "instructionAccountNode", "name": "delegate", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Owner of the delegated account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master Edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"], "defaultValue": { "kind": "programIdValueNode" } }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of metadata"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token account of mint"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "argumentValueNode", "name": "tokenOwner" } } ] } }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or token owner"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["SPL Token Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 44 } }, { "kind": "instructionArgumentNode", "name": "delegateStandardV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 6 } }, { "kind": "instructionArgumentNode", "name": "amount", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, { "kind": "instructionArgumentNode", "name": "tokenOwner", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "identityValueNode" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "delegateLockedTransferV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Delegate record account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "token" } } ] } }, { "kind": "instructionAccountNode", "name": "delegate", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Owner of the delegated account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master Edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "argumentValueNode", "name": "tokenStandard" }, "value": { "kind": "enumValueNode", "variant": "programmableNonFungible", "enum": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "token" } } ] } } }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of metadata"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token account of mint"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "argumentValueNode", "name": "tokenOwner" } } ] } }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or token owner"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["SPL Token Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 44 } }, { "kind": "instructionArgumentNode", "name": "delegateLockedTransferV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 7 } }, { "kind": "instructionArgumentNode", "name": "amount", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } }, { "kind": "instructionArgumentNode", "name": "lockedAddress", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "instructionArgumentNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, { "kind": "instructionArgumentNode", "name": "tokenOwner", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "identityValueNode" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "delegateProgrammableConfigV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Delegate record account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadataDelegateRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "delegateRole", "value": { "kind": "enumValueNode", "variant": "programmableConfig", "enum": { "kind": "definedTypeLinkNode", "name": "metadataDelegateRole" } } }, { "kind": "pdaSeedValueNode", "name": "updateAuthority", "value": { "kind": "argumentValueNode", "name": "updateAuthority" } }, { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "delegate", "value": { "kind": "accountValueNode", "name": "delegate" } } ] } }, { "kind": "instructionAccountNode", "name": "delegate", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Owner of the delegated account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master Edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of metadata"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token account of mint"] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or token owner"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["SPL Token Program"] }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 44 } }, { "kind": "instructionArgumentNode", "name": "delegateProgrammableConfigV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 8 } }, { "kind": "instructionArgumentNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, { "kind": "instructionArgumentNode", "name": "updateAuthority", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "accountValueNode", "name": "authority" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "delegateAuthorityItemV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Delegate record account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadataDelegateRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "delegateRole", "value": { "kind": "enumValueNode", "variant": "authorityItem", "enum": { "kind": "definedTypeLinkNode", "name": "metadataDelegateRole" } } }, { "kind": "pdaSeedValueNode", "name": "updateAuthority", "value": { "kind": "argumentValueNode", "name": "updateAuthority" } }, { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "delegate", "value": { "kind": "accountValueNode", "name": "delegate" } } ] } }, { "kind": "instructionAccountNode", "name": "delegate", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Owner of the delegated account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master Edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of metadata"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token account of mint"] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or token owner"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["SPL Token Program"] }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 44 } }, { "kind": "instructionArgumentNode", "name": "delegateAuthorityItemV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 9 } }, { "kind": "instructionArgumentNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, { "kind": "instructionArgumentNode", "name": "updateAuthority", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "accountValueNode", "name": "authority" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "delegateDataItemV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Delegate record account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadataDelegateRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "delegateRole", "value": { "kind": "enumValueNode", "variant": "dataItem", "enum": { "kind": "definedTypeLinkNode", "name": "metadataDelegateRole" } } }, { "kind": "pdaSeedValueNode", "name": "updateAuthority", "value": { "kind": "argumentValueNode", "name": "updateAuthority" } }, { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "delegate", "value": { "kind": "accountValueNode", "name": "delegate" } } ] } }, { "kind": "instructionAccountNode", "name": "delegate", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Owner of the delegated account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master Edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of metadata"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token account of mint"] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or token owner"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["SPL Token Program"] }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 44 } }, { "kind": "instructionArgumentNode", "name": "delegateDataItemV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 10 } }, { "kind": "instructionArgumentNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, { "kind": "instructionArgumentNode", "name": "updateAuthority", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "accountValueNode", "name": "authority" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "delegateCollectionItemV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Delegate record account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadataDelegateRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "delegateRole", "value": { "kind": "enumValueNode", "variant": "collectionItem", "enum": { "kind": "definedTypeLinkNode", "name": "metadataDelegateRole" } } }, { "kind": "pdaSeedValueNode", "name": "updateAuthority", "value": { "kind": "argumentValueNode", "name": "updateAuthority" } }, { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "delegate", "value": { "kind": "accountValueNode", "name": "delegate" } } ] } }, { "kind": "instructionAccountNode", "name": "delegate", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Owner of the delegated account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master Edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of metadata"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token account of mint"] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or token owner"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["SPL Token Program"] }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 44 } }, { "kind": "instructionArgumentNode", "name": "delegateCollectionItemV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 11 } }, { "kind": "instructionArgumentNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, { "kind": "instructionArgumentNode", "name": "updateAuthority", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "accountValueNode", "name": "authority" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "delegateProgrammableConfigItemV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Delegate record account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadataDelegateRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "delegateRole", "value": { "kind": "enumValueNode", "variant": "programmableConfigItem", "enum": { "kind": "definedTypeLinkNode", "name": "metadataDelegateRole" } } }, { "kind": "pdaSeedValueNode", "name": "updateAuthority", "value": { "kind": "argumentValueNode", "name": "updateAuthority" } }, { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "delegate", "value": { "kind": "accountValueNode", "name": "delegate" } } ] } }, { "kind": "instructionAccountNode", "name": "delegate", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Owner of the delegated account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master Edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of metadata"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token account of mint"] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or token owner"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["SPL Token Program"] }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 44 } }, { "kind": "instructionArgumentNode", "name": "delegateProgrammableConfigItemV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 12 } }, { "kind": "instructionArgumentNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, { "kind": "instructionArgumentNode", "name": "updateAuthority", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "accountValueNode", "name": "authority" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "delegatePrintDelegateV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Delegate record account"] }, { "kind": "instructionAccountNode", "name": "delegate", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Owner of the delegated account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master Edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of metadata"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token account of mint"] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or token owner"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["SPL Token Program"] }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 44 } }, { "kind": "instructionArgumentNode", "name": "delegatePrintDelegateV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 13 } }, { "kind": "instructionArgumentNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] } ] }, { "kind": "instructionNode", "name": "revoke", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Delegate record account"] }, { "kind": "instructionAccountNode", "name": "delegate", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Owner of the delegated account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master Edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of metadata"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token account of mint"] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or token owner"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["SPL Token Program"] }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 45 } }, { "kind": "instructionArgumentNode", "name": "revokeArgs", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "revokeArgs" } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "subInstructions": [ { "kind": "instructionNode", "name": "revokeCollectionV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Delegate record account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadataDelegateRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "delegateRole", "value": { "kind": "enumValueNode", "variant": "collection", "enum": { "kind": "definedTypeLinkNode", "name": "metadataDelegateRole" } } }, { "kind": "pdaSeedValueNode", "name": "updateAuthority", "value": { "kind": "argumentValueNode", "name": "updateAuthority" } }, { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "delegate", "value": { "kind": "accountValueNode", "name": "delegate" } } ] } }, { "kind": "instructionAccountNode", "name": "delegate", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Owner of the delegated account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master Edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of metadata"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token account of mint"] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or token owner"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["SPL Token Program"] }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 45 } }, { "kind": "instructionArgumentNode", "name": "revokeCollectionV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 0 } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, { "kind": "instructionArgumentNode", "name": "updateAuthority", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "accountValueNode", "name": "authority" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "revokeSaleV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Delegate record account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "token" } } ] } }, { "kind": "instructionAccountNode", "name": "delegate", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Owner of the delegated account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master Edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "argumentValueNode", "name": "tokenStandard" }, "value": { "kind": "enumValueNode", "variant": "programmableNonFungible", "enum": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "token" } } ] } } }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of metadata"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token account of mint"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "argumentValueNode", "name": "tokenOwner" } } ] } }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or token owner"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["SPL Token Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 45 } }, { "kind": "instructionArgumentNode", "name": "revokeSaleV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, { "kind": "instructionArgumentNode", "name": "tokenOwner", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "identityValueNode" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "revokeTransferV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Delegate record account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "token" } } ] } }, { "kind": "instructionAccountNode", "name": "delegate", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Owner of the delegated account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master Edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "argumentValueNode", "name": "tokenStandard" }, "value": { "kind": "enumValueNode", "variant": "programmableNonFungible", "enum": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "token" } } ] } } }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of metadata"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token account of mint"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "argumentValueNode", "name": "tokenOwner" } } ] } }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or token owner"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["SPL Token Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 45 } }, { "kind": "instructionArgumentNode", "name": "revokeTransferV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 2 } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, { "kind": "instructionArgumentNode", "name": "tokenOwner", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "identityValueNode" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "revokeDataV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Delegate record account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadataDelegateRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "delegateRole", "value": { "kind": "enumValueNode", "variant": "data", "enum": { "kind": "definedTypeLinkNode", "name": "metadataDelegateRole" } } }, { "kind": "pdaSeedValueNode", "name": "updateAuthority", "value": { "kind": "argumentValueNode", "name": "updateAuthority" } }, { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "delegate", "value": { "kind": "accountValueNode", "name": "delegate" } } ] } }, { "kind": "instructionAccountNode", "name": "delegate", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Owner of the delegated account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master Edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of metadata"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token account of mint"] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or token owner"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["SPL Token Program"] }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 45 } }, { "kind": "instructionArgumentNode", "name": "revokeDataV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 3 } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, { "kind": "instructionArgumentNode", "name": "updateAuthority", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "accountValueNode", "name": "authority" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "revokeUtilityV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Delegate record account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "token" } } ] } }, { "kind": "instructionAccountNode", "name": "delegate", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Owner of the delegated account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master Edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "argumentValueNode", "name": "tokenStandard" }, "value": { "kind": "enumValueNode", "variant": "programmableNonFungible", "enum": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "token" } } ] } } }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of metadata"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token account of mint"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "argumentValueNode", "name": "tokenOwner" } } ] } }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or token owner"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["SPL Token Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 45 } }, { "kind": "instructionArgumentNode", "name": "revokeUtilityV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 4 } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, { "kind": "instructionArgumentNode", "name": "tokenOwner", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "identityValueNode" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "revokeStakingV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Delegate record account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "token" } } ] } }, { "kind": "instructionAccountNode", "name": "delegate", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Owner of the delegated account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master Edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "argumentValueNode", "name": "tokenStandard" }, "value": { "kind": "enumValueNode", "variant": "programmableNonFungible", "enum": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "token" } } ] } } }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of metadata"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token account of mint"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "argumentValueNode", "name": "tokenOwner" } } ] } }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or token owner"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["SPL Token Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 45 } }, { "kind": "instructionArgumentNode", "name": "revokeStakingV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 5 } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, { "kind": "instructionArgumentNode", "name": "tokenOwner", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "identityValueNode" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "revokeStandardV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Delegate record account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "token" } } ] } }, { "kind": "instructionAccountNode", "name": "delegate", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Owner of the delegated account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master Edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"], "defaultValue": { "kind": "programIdValueNode" } }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of metadata"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token account of mint"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "argumentValueNode", "name": "tokenOwner" } } ] } }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or token owner"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["SPL Token Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 45 } }, { "kind": "instructionArgumentNode", "name": "revokeStandardV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 6 } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, { "kind": "instructionArgumentNode", "name": "tokenOwner", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "identityValueNode" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "revokeLockedTransferV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Delegate record account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "token" } } ] } }, { "kind": "instructionAccountNode", "name": "delegate", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Owner of the delegated account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master Edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "argumentValueNode", "name": "tokenStandard" }, "value": { "kind": "enumValueNode", "variant": "programmableNonFungible", "enum": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "token" } } ] } } }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of metadata"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token account of mint"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "argumentValueNode", "name": "tokenOwner" } } ] } }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or token owner"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["SPL Token Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 45 } }, { "kind": "instructionArgumentNode", "name": "revokeLockedTransferV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 7 } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, { "kind": "instructionArgumentNode", "name": "tokenOwner", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "identityValueNode" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "revokeProgrammableConfigV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Delegate record account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadataDelegateRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "delegateRole", "value": { "kind": "enumValueNode", "variant": "programmableConfig", "enum": { "kind": "definedTypeLinkNode", "name": "metadataDelegateRole" } } }, { "kind": "pdaSeedValueNode", "name": "updateAuthority", "value": { "kind": "argumentValueNode", "name": "updateAuthority" } }, { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "delegate", "value": { "kind": "accountValueNode", "name": "delegate" } } ] } }, { "kind": "instructionAccountNode", "name": "delegate", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Owner of the delegated account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master Edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of metadata"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token account of mint"] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or token owner"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["SPL Token Program"] }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 45 } }, { "kind": "instructionArgumentNode", "name": "revokeProgrammableConfigV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 8 } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, { "kind": "instructionArgumentNode", "name": "updateAuthority", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "accountValueNode", "name": "authority" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "revokeMigrationV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Delegate record account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "token" } } ] } }, { "kind": "instructionAccountNode", "name": "delegate", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Owner of the delegated account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master Edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "argumentValueNode", "name": "tokenStandard" }, "value": { "kind": "enumValueNode", "variant": "programmableNonFungible", "enum": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "token" } } ] } } }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of metadata"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token account of mint"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "argumentValueNode", "name": "tokenOwner" } } ] } }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or token owner"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["SPL Token Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 45 } }, { "kind": "instructionArgumentNode", "name": "revokeMigrationV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 9 } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, { "kind": "instructionArgumentNode", "name": "tokenOwner", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "identityValueNode" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "revokeAuthorityItemV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Delegate record account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadataDelegateRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "delegateRole", "value": { "kind": "enumValueNode", "variant": "authorityItem", "enum": { "kind": "definedTypeLinkNode", "name": "metadataDelegateRole" } } }, { "kind": "pdaSeedValueNode", "name": "updateAuthority", "value": { "kind": "argumentValueNode", "name": "updateAuthority" } }, { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "delegate", "value": { "kind": "accountValueNode", "name": "delegate" } } ] } }, { "kind": "instructionAccountNode", "name": "delegate", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Owner of the delegated account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master Edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of metadata"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token account of mint"] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or token owner"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["SPL Token Program"] }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 45 } }, { "kind": "instructionArgumentNode", "name": "revokeAuthorityItemV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 10 } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, { "kind": "instructionArgumentNode", "name": "updateAuthority", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "accountValueNode", "name": "authority" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "revokeDataItemV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Delegate record account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadataDelegateRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "delegateRole", "value": { "kind": "enumValueNode", "variant": "dataItem", "enum": { "kind": "definedTypeLinkNode", "name": "metadataDelegateRole" } } }, { "kind": "pdaSeedValueNode", "name": "updateAuthority", "value": { "kind": "argumentValueNode", "name": "updateAuthority" } }, { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "delegate", "value": { "kind": "accountValueNode", "name": "delegate" } } ] } }, { "kind": "instructionAccountNode", "name": "delegate", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Owner of the delegated account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master Edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of metadata"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token account of mint"] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or token owner"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["SPL Token Program"] }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 45 } }, { "kind": "instructionArgumentNode", "name": "revokeDataItemV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 11 } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, { "kind": "instructionArgumentNode", "name": "updateAuthority", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "accountValueNode", "name": "authority" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "revokeCollectionItemV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Delegate record account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadataDelegateRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "delegateRole", "value": { "kind": "enumValueNode", "variant": "collectionItem", "enum": { "kind": "definedTypeLinkNode", "name": "metadataDelegateRole" } } }, { "kind": "pdaSeedValueNode", "name": "updateAuthority", "value": { "kind": "argumentValueNode", "name": "updateAuthority" } }, { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "delegate", "value": { "kind": "accountValueNode", "name": "delegate" } } ] } }, { "kind": "instructionAccountNode", "name": "delegate", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Owner of the delegated account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master Edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of metadata"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token account of mint"] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or token owner"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["SPL Token Program"] }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 45 } }, { "kind": "instructionArgumentNode", "name": "revokeCollectionItemV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 12 } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, { "kind": "instructionArgumentNode", "name": "updateAuthority", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "accountValueNode", "name": "authority" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "revokeProgrammableConfigItemV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Delegate record account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadataDelegateRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "delegateRole", "value": { "kind": "enumValueNode", "variant": "programmableConfigItem", "enum": { "kind": "definedTypeLinkNode", "name": "metadataDelegateRole" } } }, { "kind": "pdaSeedValueNode", "name": "updateAuthority", "value": { "kind": "argumentValueNode", "name": "updateAuthority" } }, { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "delegate", "value": { "kind": "accountValueNode", "name": "delegate" } } ] } }, { "kind": "instructionAccountNode", "name": "delegate", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Owner of the delegated account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master Edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of metadata"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token account of mint"] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or token owner"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["SPL Token Program"] }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 45 } }, { "kind": "instructionArgumentNode", "name": "revokeProgrammableConfigItemV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 13 } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, { "kind": "instructionArgumentNode", "name": "updateAuthority", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "accountValueNode", "name": "authority" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "revokePrintDelegateV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Delegate record account"] }, { "kind": "instructionAccountNode", "name": "delegate", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Owner of the delegated account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master Edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of metadata"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token account of mint"] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or token owner"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["SPL Token Program"] }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 45 } }, { "kind": "instructionArgumentNode", "name": "revokePrintDelegateV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 14 } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] } ] }, { "kind": "instructionNode", "name": "lock", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Delegate or freeze authority"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "tokenOwner", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token owner account"], "defaultValue": { "kind": "resolverValueNode", "name": "resolveOptionalTokenOwner", "docs": [] } }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "accountValueNode", "name": "tokenOwner" } } ] } }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "edition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "argumentValueNode", "name": "tokenStandard" }, "value": { "kind": "enumValueNode", "variant": "programmableNonFungible", "enum": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "token" } } ] } } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["SPL Token Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "argumentValueNode", "name": "tokenStandard" }, "value": { "kind": "enumValueNode", "variant": "programmableNonFungible", "enum": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, "ifFalse": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } } }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 46 } }, { "kind": "instructionArgumentNode", "name": "lockArgs", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "lockArgs" } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "subInstructions": [ { "kind": "instructionNode", "name": "lockV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Delegate or freeze authority"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "tokenOwner", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token owner account"], "defaultValue": { "kind": "resolverValueNode", "name": "resolveOptionalTokenOwner", "docs": [] } }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "accountValueNode", "name": "tokenOwner" } } ] } }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "edition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "argumentValueNode", "name": "tokenStandard" }, "value": { "kind": "enumValueNode", "variant": "programmableNonFungible", "enum": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "token" } } ] } } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["SPL Token Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "argumentValueNode", "name": "tokenStandard" }, "value": { "kind": "enumValueNode", "variant": "programmableNonFungible", "enum": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, "ifFalse": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } } }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 46 } }, { "kind": "instructionArgumentNode", "name": "lockV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 0 } }, { "kind": "instructionArgumentNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] } ] }, { "kind": "instructionNode", "name": "unlock", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Delegate or freeze authority"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "tokenOwner", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token owner account"], "defaultValue": { "kind": "resolverValueNode", "name": "resolveOptionalTokenOwner", "docs": [] } }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "accountValueNode", "name": "tokenOwner" } } ] } }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "edition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "argumentValueNode", "name": "tokenStandard" }, "value": { "kind": "enumValueNode", "variant": "programmableNonFungible", "enum": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "token" } } ] } } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["SPL Token Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "argumentValueNode", "name": "tokenStandard" }, "value": { "kind": "enumValueNode", "variant": "programmableNonFungible", "enum": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, "ifFalse": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } } }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 47 } }, { "kind": "instructionArgumentNode", "name": "unlockArgs", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "unlockArgs" } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "subInstructions": [ { "kind": "instructionNode", "name": "unlockV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Delegate or freeze authority"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "tokenOwner", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token owner account"], "defaultValue": { "kind": "resolverValueNode", "name": "resolveOptionalTokenOwner", "docs": [] } }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "accountValueNode", "name": "tokenOwner" } } ] } }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "edition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Edition account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "resolverValueNode", "name": "resolveIsNonFungible", "docs": [], "dependsOn": [ { "kind": "argumentValueNode", "name": "tokenStandard" } ] }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "argumentValueNode", "name": "tokenStandard" }, "value": { "kind": "enumValueNode", "variant": "programmableNonFungible", "enum": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "token" } } ] } } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["SPL Token Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "argumentValueNode", "name": "tokenStandard" }, "value": { "kind": "enumValueNode", "variant": "programmableNonFungible", "enum": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, "ifFalse": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } } }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 47 } }, { "kind": "instructionArgumentNode", "name": "unlockV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 0 } }, { "kind": "instructionArgumentNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] } ] }, { "kind": "instructionNode", "name": "migrate", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "edition", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Edition account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token account"] }, { "kind": "instructionAccountNode", "name": "tokenOwner", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Token account owner"] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint account"] }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority"], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "collectionMetadata", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Collection metadata account"] }, { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Delegate record account"] }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token record account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "token" } } ] } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instruction sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["SPL Token Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 48 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "transfer", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "accountValueNode", "name": "tokenOwner" } } ] } }, { "kind": "instructionAccountNode", "name": "tokenOwner", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Token account owner"], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "destinationToken", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Destination token account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "accountValueNode", "name": "destinationOwner" } } ] } }, { "kind": "instructionAccountNode", "name": "destinationOwner", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Destination token account owner"] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of token asset"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata (pda of ['metadata', program id, mint id])"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "edition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Edition of token asset"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "argumentValueNode", "name": "tokenStandard" }, "value": { "kind": "enumValueNode", "variant": "programmableNonFungible", "enum": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Owner token record account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "argumentValueNode", "name": "tokenStandard" }, "value": { "kind": "enumValueNode", "variant": "programmableNonFungible", "enum": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "token" } } ] } } }, { "kind": "instructionAccountNode", "name": "destinationTokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Destination token record account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "argumentValueNode", "name": "tokenStandard" }, "value": { "kind": "enumValueNode", "variant": "programmableNonFungible", "enum": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "destinationToken" } }, { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Transfer authority (token owner or delegate)"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["SPL Token Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } }, { "kind": "instructionAccountNode", "name": "splAtaProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["SPL Associated Token Account program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", "identifier": "splAssociatedToken" } }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 49 } }, { "kind": "instructionArgumentNode", "name": "transferArgs", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "transferArgs" } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "subInstructions": [ { "kind": "instructionNode", "name": "transferV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "accountValueNode", "name": "tokenOwner" } } ] } }, { "kind": "instructionAccountNode", "name": "tokenOwner", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Token account owner"], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "destinationToken", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Destination token account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "accountValueNode", "name": "destinationOwner" } } ] } }, { "kind": "instructionAccountNode", "name": "destinationOwner", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Destination token account owner"] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of token asset"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata (pda of ['metadata', program id, mint id])"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "edition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Edition of token asset"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "argumentValueNode", "name": "tokenStandard" }, "value": { "kind": "enumValueNode", "variant": "programmableNonFungible", "enum": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "tokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Owner token record account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "argumentValueNode", "name": "tokenStandard" }, "value": { "kind": "enumValueNode", "variant": "programmableNonFungible", "enum": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "token" } } ] } } }, { "kind": "instructionAccountNode", "name": "destinationTokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Destination token record account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "argumentValueNode", "name": "tokenStandard" }, "value": { "kind": "enumValueNode", "variant": "programmableNonFungible", "enum": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "destinationToken" } }, { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } } }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Transfer authority (token owner or delegate)"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["SPL Token Program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } }, { "kind": "instructionAccountNode", "name": "splAtaProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["SPL Associated Token Account program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", "identifier": "splAssociatedToken" } }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 49 } }, { "kind": "instructionArgumentNode", "name": "transferV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 0 } }, { "kind": "instructionArgumentNode", "name": "amount", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } }, { "kind": "instructionArgumentNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] } ] }, { "kind": "instructionNode", "name": "update", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or delegate"], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Delegate record PDA"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token account"] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "edition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Edition account"] }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 50 } }, { "kind": "instructionArgumentNode", "name": "updateArgs", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "updateArgs" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "subInstructions": [ { "kind": "instructionNode", "name": "updateV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or delegate"], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Delegate record PDA"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token account"] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "edition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Edition account"] }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 50 } }, { "kind": "instructionArgumentNode", "name": "updateV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 0 } }, { "kind": "instructionArgumentNode", "name": "newUpdateAuthority", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "publicKeyTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "instructionArgumentNode", "name": "data", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "data" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "instructionArgumentNode", "name": "primarySaleHappened", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "instructionArgumentNode", "name": "isMutable", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "instructionArgumentNode", "name": "collection", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "collectionToggle" }, "defaultValue": { "kind": "enumValueNode", "variant": "none", "enum": { "kind": "definedTypeLinkNode", "name": "collectionToggle" } } }, { "kind": "instructionArgumentNode", "name": "collectionDetails", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "collectionDetailsToggle" }, "defaultValue": { "kind": "enumValueNode", "variant": "none", "enum": { "kind": "definedTypeLinkNode", "name": "collectionDetailsToggle" } } }, { "kind": "instructionArgumentNode", "name": "uses", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "usesToggle" }, "defaultValue": { "kind": "enumValueNode", "variant": "none", "enum": { "kind": "definedTypeLinkNode", "name": "usesToggle" } } }, { "kind": "instructionArgumentNode", "name": "ruleSet", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "ruleSetToggle" }, "defaultValue": { "kind": "enumValueNode", "variant": "none", "enum": { "kind": "definedTypeLinkNode", "name": "ruleSetToggle" } } }, { "kind": "instructionArgumentNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "updateAsUpdateAuthorityV2", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or delegate"], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Delegate record PDA"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token account"] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "edition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Edition account"] }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 50 } }, { "kind": "instructionArgumentNode", "name": "updateAsUpdateAuthorityV2Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } }, { "kind": "instructionArgumentNode", "name": "newUpdateAuthority", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "publicKeyTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "instructionArgumentNode", "name": "data", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "data" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "instructionArgumentNode", "name": "primarySaleHappened", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "instructionArgumentNode", "name": "isMutable", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "instructionArgumentNode", "name": "collection", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "collectionToggle" }, "defaultValue": { "kind": "enumValueNode", "variant": "none", "enum": { "kind": "definedTypeLinkNode", "name": "collectionToggle" } } }, { "kind": "instructionArgumentNode", "name": "collectionDetails", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "collectionDetailsToggle" }, "defaultValue": { "kind": "enumValueNode", "variant": "none", "enum": { "kind": "definedTypeLinkNode", "name": "collectionDetailsToggle" } } }, { "kind": "instructionArgumentNode", "name": "uses", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "usesToggle" }, "defaultValue": { "kind": "enumValueNode", "variant": "none", "enum": { "kind": "definedTypeLinkNode", "name": "usesToggle" } } }, { "kind": "instructionArgumentNode", "name": "ruleSet", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "ruleSetToggle" }, "defaultValue": { "kind": "enumValueNode", "variant": "none", "enum": { "kind": "definedTypeLinkNode", "name": "ruleSetToggle" } } }, { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "tokenStandard" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "instructionArgumentNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "updateAsAuthorityItemDelegateV2", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or delegate"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Delegate record PDA"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadataDelegateRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "delegateRole", "value": { "kind": "enumValueNode", "variant": "authorityItem", "enum": { "kind": "definedTypeLinkNode", "name": "metadataDelegateRole" } } }, { "kind": "pdaSeedValueNode", "name": "updateAuthority", "value": { "kind": "argumentValueNode", "name": "updateAuthority" } }, { "kind": "pdaSeedValueNode", "name": "delegate", "value": { "kind": "accountValueNode", "name": "authority" } }, { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "token", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token account"] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "edition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Edition account"] }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 50 } }, { "kind": "instructionArgumentNode", "name": "updateAsAuthorityItemDelegateV2Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 2 } }, { "kind": "instructionArgumentNode", "name": "newUpdateAuthority", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "publicKeyTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "instructionArgumentNode", "name": "primarySaleHappened", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "instructionArgumentNode", "name": "isMutable", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "tokenStandard" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "instructionArgumentNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "updateAuthority", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "identityValueNode" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "updateAsCollectionDelegateV2", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or delegate"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Delegate record PDA"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadataDelegateRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "argumentValueNode", "name": "delegateMint" } }, { "kind": "pdaSeedValueNode", "name": "delegateRole", "value": { "kind": "enumValueNode", "variant": "collection", "enum": { "kind": "definedTypeLinkNode", "name": "metadataDelegateRole" } } }, { "kind": "pdaSeedValueNode", "name": "updateAuthority", "value": { "kind": "argumentValueNode", "name": "delegateUpdateAuthority" } }, { "kind": "pdaSeedValueNode", "name": "delegate", "value": { "kind": "accountValueNode", "name": "authority" } } ] } }, { "kind": "instructionAccountNode", "name": "token", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token account"] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "edition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Edition account"] }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 50 } }, { "kind": "instructionArgumentNode", "name": "updateAsCollectionDelegateV2Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 3 } }, { "kind": "instructionArgumentNode", "name": "collection", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "collectionToggle" }, "defaultValue": { "kind": "enumValueNode", "variant": "none", "enum": { "kind": "definedTypeLinkNode", "name": "collectionToggle" } } }, { "kind": "instructionArgumentNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "delegateMint", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "instructionArgumentNode", "name": "delegateUpdateAuthority", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "identityValueNode" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "updateAsDataDelegateV2", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or delegate"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Delegate record PDA"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadataDelegateRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "argumentValueNode", "name": "delegateMint" } }, { "kind": "pdaSeedValueNode", "name": "delegateRole", "value": { "kind": "enumValueNode", "variant": "data", "enum": { "kind": "definedTypeLinkNode", "name": "metadataDelegateRole" } } }, { "kind": "pdaSeedValueNode", "name": "updateAuthority", "value": { "kind": "argumentValueNode", "name": "delegateUpdateAuthority" } }, { "kind": "pdaSeedValueNode", "name": "delegate", "value": { "kind": "accountValueNode", "name": "authority" } } ] } }, { "kind": "instructionAccountNode", "name": "token", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token account"] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "edition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Edition account"] }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 50 } }, { "kind": "instructionArgumentNode", "name": "updateAsDataDelegateV2Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 4 } }, { "kind": "instructionArgumentNode", "name": "data", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "data" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "instructionArgumentNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "delegateMint", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "instructionArgumentNode", "name": "delegateUpdateAuthority", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "identityValueNode" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "updateAsProgrammableConfigDelegateV2", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or delegate"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Delegate record PDA"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadataDelegateRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "argumentValueNode", "name": "delegateMint" } }, { "kind": "pdaSeedValueNode", "name": "delegateRole", "value": { "kind": "enumValueNode", "variant": "programmableConfig", "enum": { "kind": "definedTypeLinkNode", "name": "metadataDelegateRole" } } }, { "kind": "pdaSeedValueNode", "name": "updateAuthority", "value": { "kind": "argumentValueNode", "name": "delegateUpdateAuthority" } }, { "kind": "pdaSeedValueNode", "name": "delegate", "value": { "kind": "accountValueNode", "name": "authority" } } ] } }, { "kind": "instructionAccountNode", "name": "token", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Token account"] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "edition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Edition account"] }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 50 } }, { "kind": "instructionArgumentNode", "name": "updateAsProgrammableConfigDelegateV2Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 5 } }, { "kind": "instructionArgumentNode", "name": "ruleSet", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "ruleSetToggle" }, "defaultValue": { "kind": "enumValueNode", "variant": "none", "enum": { "kind": "definedTypeLinkNode", "name": "ruleSetToggle" } } }, { "kind": "instructionArgumentNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "delegateMint", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "accountValueNode", "name": "mint" } }, { "kind": "instructionArgumentNode", "name": "delegateUpdateAuthority", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "identityValueNode" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "updateAsDataItemDelegateV2", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or delegate"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Delegate record PDA"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadataDelegateRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "delegateRole", "value": { "kind": "enumValueNode", "variant": "dataItem", "enum": { "kind": "definedTypeLinkNode", "name": "metadataDelegateRole" } } }, { "kind": "pdaSeedValueNode", "name": "updateAuthority", "value": { "kind": "argumentValueNode", "name": "updateAuthority" } }, { "kind": "pdaSeedValueNode", "name": "delegate", "value": { "kind": "accountValueNode", "name": "authority" } }, { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "token", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token account"] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "edition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Edition account"] }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 50 } }, { "kind": "instructionArgumentNode", "name": "updateAsDataItemDelegateV2Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 6 } }, { "kind": "instructionArgumentNode", "name": "data", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "data" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "instructionArgumentNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "updateAuthority", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "identityValueNode" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "updateAsCollectionItemDelegateV2", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or delegate"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Delegate record PDA"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadataDelegateRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "delegateRole", "value": { "kind": "enumValueNode", "variant": "collectionItem", "enum": { "kind": "definedTypeLinkNode", "name": "metadataDelegateRole" } } }, { "kind": "pdaSeedValueNode", "name": "updateAuthority", "value": { "kind": "argumentValueNode", "name": "updateAuthority" } }, { "kind": "pdaSeedValueNode", "name": "delegate", "value": { "kind": "accountValueNode", "name": "authority" } }, { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "token", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token account"] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "edition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Edition account"] }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 50 } }, { "kind": "instructionArgumentNode", "name": "updateAsCollectionItemDelegateV2Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 7 } }, { "kind": "instructionArgumentNode", "name": "collection", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "collectionToggle" }, "defaultValue": { "kind": "enumValueNode", "variant": "none", "enum": { "kind": "definedTypeLinkNode", "name": "collectionToggle" } } }, { "kind": "instructionArgumentNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "updateAuthority", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "identityValueNode" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "updateAsProgrammableConfigItemDelegateV2", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Update authority or delegate"], "defaultValue": { "kind": "accountValueNode", "name": "payer" } }, { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Delegate record PDA"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadataDelegateRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "delegateRole", "value": { "kind": "enumValueNode", "variant": "programmableConfigItem", "enum": { "kind": "definedTypeLinkNode", "name": "metadataDelegateRole" } } }, { "kind": "pdaSeedValueNode", "name": "updateAuthority", "value": { "kind": "argumentValueNode", "name": "updateAuthority" } }, { "kind": "pdaSeedValueNode", "name": "delegate", "value": { "kind": "accountValueNode", "name": "authority" } }, { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "token", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Token account"] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "edition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Edition account"] }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 50 } }, { "kind": "instructionArgumentNode", "name": "updateAsProgrammableConfigItemDelegateV2Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 8 } }, { "kind": "instructionArgumentNode", "name": "ruleSet", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "ruleSetToggle" }, "defaultValue": { "kind": "enumValueNode", "variant": "none", "enum": { "kind": "definedTypeLinkNode", "name": "ruleSetToggle" } } }, { "kind": "instructionArgumentNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "updateAuthority", "docs": [], "type": { "kind": "publicKeyTypeNode" }, "defaultValue": { "kind": "identityValueNode" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] } ] }, { "kind": "instructionNode", "name": "use", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Token owner or delegate"], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Delegate record PDA"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token account"] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "edition", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Edition account"] }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["SPL Token Program"] }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 51 } }, { "kind": "instructionArgumentNode", "name": "useArgs", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "useArgs" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "subInstructions": [ { "kind": "instructionNode", "name": "useV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Token owner or delegate"], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Delegate record PDA"] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token account"] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint account"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "edition", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Edition account"] }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["SPL Token Program"] }, { "kind": "instructionAccountNode", "name": "authorizationRulesProgram", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules Program"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "authorizationRules" }, "ifTrue": { "kind": "publicKeyValueNode", "publicKey": "auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg", "identifier": "mplTokenAuthRules" } } }, { "kind": "instructionAccountNode", "name": "authorizationRules", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token Authorization Rules account"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 51 } }, { "kind": "instructionArgumentNode", "name": "useV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 0 } }, { "kind": "instructionArgumentNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] } ] }, { "kind": "instructionNode", "name": "verify", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Creator to verify, collection update authority or delegate"], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Delegate record PDA"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"] }, { "kind": "instructionAccountNode", "name": "collectionMint", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Mint of the Collection"] }, { "kind": "instructionAccountNode", "name": "collectionMetadata", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Metadata Account of the Collection"] }, { "kind": "instructionAccountNode", "name": "collectionMasterEdition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master Edition Account of the Collection Token"] }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 52 } }, { "kind": "instructionArgumentNode", "name": "verificationArgs", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "verificationArgs" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "subInstructions": [ { "kind": "instructionNode", "name": "verifyCreatorV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Creator to verify, collection update authority or delegate"], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Delegate record PDA"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"] }, { "kind": "instructionAccountNode", "name": "collectionMint", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Mint of the Collection"] }, { "kind": "instructionAccountNode", "name": "collectionMetadata", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Metadata Account of the Collection"] }, { "kind": "instructionAccountNode", "name": "collectionMasterEdition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master Edition Account of the Collection Token"] }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 52 } }, { "kind": "instructionArgumentNode", "name": "verifyCreatorV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 0 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "verifyCollectionV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Creator to verify, collection update authority or delegate"], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Delegate record PDA"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"] }, { "kind": "instructionAccountNode", "name": "collectionMint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of the Collection"] }, { "kind": "instructionAccountNode", "name": "collectionMetadata", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Metadata Account of the Collection"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "collectionMint" } } ] } }, { "kind": "instructionAccountNode", "name": "collectionMasterEdition", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Master Edition Account of the Collection Token"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "collectionMint" } } ] } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 52 } }, { "kind": "instructionArgumentNode", "name": "verifyCollectionV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] } ] }, { "kind": "instructionNode", "name": "unverify", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": [ "Creator to verify, collection (or metadata if parent burned) update authority or delegate" ], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Delegate record PDA"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"] }, { "kind": "instructionAccountNode", "name": "collectionMint", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Mint of the Collection"] }, { "kind": "instructionAccountNode", "name": "collectionMetadata", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Metadata Account of the Collection"] }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 53 } }, { "kind": "instructionArgumentNode", "name": "verificationArgs", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "verificationArgs" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "subInstructions": [ { "kind": "instructionNode", "name": "unverifyCreatorV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": [ "Creator to verify, collection (or metadata if parent burned) update authority or delegate" ], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Delegate record PDA"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"] }, { "kind": "instructionAccountNode", "name": "collectionMint", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Mint of the Collection"] }, { "kind": "instructionAccountNode", "name": "collectionMetadata", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Metadata Account of the Collection"] }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 53 } }, { "kind": "instructionArgumentNode", "name": "unverifyCreatorV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 0 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "unverifyCollectionV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": [ "Creator to verify, collection (or metadata if parent burned) update authority or delegate" ], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "delegateRecord", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Delegate record PDA"] }, { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata account"] }, { "kind": "instructionAccountNode", "name": "collectionMint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of the Collection"] }, { "kind": "instructionAccountNode", "name": "collectionMetadata", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Metadata Account of the Collection"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "collectionMint" } } ] } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 53 } }, { "kind": "instructionArgumentNode", "name": "unverifyCollectionV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] } ] }, { "kind": "instructionNode", "name": "collect", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Authority to collect fees"], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "recipient", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The account to transfer collected fees to"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 54 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "print", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "editionMetadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["New Metadata key (pda of ['metadata', program id, mint id])"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "editionMint" } } ] } }, { "kind": "instructionAccountNode", "name": "edition", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["New Edition (pda of ['metadata', program id, mint id, 'edition'])"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "editionMint" } } ] } }, { "kind": "instructionAccountNode", "name": "editionMint", "isWritable": true, "isSigner": "either", "isOptional": false, "docs": ["Mint of new token - THIS WILL TRANSFER AUTHORITY AWAY FROM THIS KEY"] }, { "kind": "instructionAccountNode", "name": "editionTokenAccountOwner", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Owner of the token account of new token"], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "editionTokenAccount", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token account of new token"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "editionMint" } }, { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "accountValueNode", "name": "editionTokenAccountOwner" } } ] } }, { "kind": "instructionAccountNode", "name": "editionMintAuthority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Mint authority of new mint"] }, { "kind": "instructionAccountNode", "name": "editionTokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "argumentValueNode", "name": "tokenStandard" }, "value": { "kind": "enumValueNode", "variant": "programmableNonFungible", "enum": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "editionMint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "editionTokenAccount" } } ] } } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [ "Master Record Edition V2 (pda of ['metadata', program id, master metadata mint id, 'edition'])" ], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "argumentValueNode", "name": "masterEditionMint" } } ] } }, { "kind": "instructionAccountNode", "name": "editionMarkerPda", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [ "Edition pda to mark creation - will be checked for pre-existence. (pda of ['metadata', program id, master metadata mint id, 'edition', edition_number]) where edition_number is NOT the edition number you pass in args but actually edition_number = floor(edition/EDITION_MARKER_BIT_SIZE)." ] }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "masterTokenAccountOwner", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["owner of token account containing master token"] }, { "kind": "instructionAccountNode", "name": "masterTokenAccount", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["token account containing token from master metadata mint"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "argumentValueNode", "name": "masterEditionMint" } }, { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "accountValueNode", "name": "masterTokenAccountOwner" } } ] } }, { "kind": "instructionAccountNode", "name": "masterMetadata", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Master record metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "argumentValueNode", "name": "masterEditionMint" } } ] } }, { "kind": "instructionAccountNode", "name": "updateAuthority", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The update authority of the master edition."], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Token program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } }, { "kind": "instructionAccountNode", "name": "splAtaProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["SPL Associated Token Account program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", "identifier": "splAssociatedToken" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 55 } }, { "kind": "instructionArgumentNode", "name": "printArgs", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "printArgs" } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "masterEditionMint", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "subInstructions": [ { "kind": "instructionNode", "name": "printV1", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "editionMetadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["New Metadata key (pda of ['metadata', program id, mint id])"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "editionMint" } } ] } }, { "kind": "instructionAccountNode", "name": "edition", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["New Edition (pda of ['metadata', program id, mint id, 'edition'])"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "editionMint" } } ] } }, { "kind": "instructionAccountNode", "name": "editionMint", "isWritable": true, "isSigner": "either", "isOptional": false, "docs": ["Mint of new token - THIS WILL TRANSFER AUTHORITY AWAY FROM THIS KEY"] }, { "kind": "instructionAccountNode", "name": "editionTokenAccountOwner", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Owner of the token account of new token"], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "editionTokenAccount", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token account of new token"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "editionMint" } }, { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "accountValueNode", "name": "editionTokenAccountOwner" } } ] } }, { "kind": "instructionAccountNode", "name": "editionMintAuthority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Mint authority of new mint"], "defaultValue": { "kind": "accountValueNode", "name": "masterTokenAccountOwner" } }, { "kind": "instructionAccountNode", "name": "editionTokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "argumentValueNode", "name": "tokenStandard" }, "value": { "kind": "enumValueNode", "variant": "programmableNonFungible", "enum": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "editionMint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "editionTokenAccount" } } ] } } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [ "Master Record Edition V2 (pda of ['metadata', program id, master metadata mint id, 'edition'])" ], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "argumentValueNode", "name": "masterEditionMint" } } ] } }, { "kind": "instructionAccountNode", "name": "editionMarkerPda", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [ "Edition pda to mark creation - will be checked for pre-existence. (pda of ['metadata', program id, master metadata mint id, 'edition', edition_number]) where edition_number is NOT the edition number you pass in args but actually edition_number = floor(edition/EDITION_MARKER_BIT_SIZE)." ], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "argumentValueNode", "name": "tokenStandard" }, "value": { "kind": "enumValueNode", "variant": "programmableNonFungible", "enum": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "editionMarkerV2" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "argumentValueNode", "name": "masterEditionMint" } } ] }, "ifFalse": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "editionMarkerFromEditionNumber" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "argumentValueNode", "name": "masterEditionMint" } }, { "kind": "pdaSeedValueNode", "name": "editionNumber", "value": { "kind": "argumentValueNode", "name": "editionNumber" } } ] } } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "masterTokenAccountOwner", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["owner of token account containing master token"], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "masterTokenAccount", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["token account containing token from master metadata mint"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "argumentValueNode", "name": "masterEditionMint" } }, { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "accountValueNode", "name": "masterTokenAccountOwner" } } ] } }, { "kind": "instructionAccountNode", "name": "masterMetadata", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Master record metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "argumentValueNode", "name": "masterEditionMint" } } ] } }, { "kind": "instructionAccountNode", "name": "updateAuthority", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The update authority of the master edition."], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Token program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } }, { "kind": "instructionAccountNode", "name": "splAtaProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["SPL Associated Token Account program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", "identifier": "splAssociatedToken" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 55 } }, { "kind": "instructionArgumentNode", "name": "printV1Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 0 } }, { "kind": "instructionArgumentNode", "name": "editionNumber", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "masterEditionMint", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "printV2", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "editionMetadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["New Metadata key (pda of ['metadata', program id, mint id])"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "editionMint" } } ] } }, { "kind": "instructionAccountNode", "name": "edition", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["New Edition (pda of ['metadata', program id, mint id, 'edition'])"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "editionMint" } } ] } }, { "kind": "instructionAccountNode", "name": "editionMint", "isWritable": true, "isSigner": "either", "isOptional": false, "docs": ["Mint of new token - THIS WILL TRANSFER AUTHORITY AWAY FROM THIS KEY"] }, { "kind": "instructionAccountNode", "name": "editionTokenAccountOwner", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Owner of the token account of new token"], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "editionTokenAccount", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token account of new token"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "editionMint" } }, { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "accountValueNode", "name": "editionTokenAccountOwner" } } ] } }, { "kind": "instructionAccountNode", "name": "editionMintAuthority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Mint authority of new mint"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "holderDelegateRecord" }, "ifTrue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "delegate" }, "ifTrue": { "kind": "accountValueNode", "name": "delegate" }, "ifFalse": { "kind": "accountValueNode", "name": "payer" } }, "ifFalse": { "kind": "accountValueNode", "name": "masterTokenAccountOwner" } } }, { "kind": "instructionAccountNode", "name": "editionTokenRecord", "isWritable": true, "isSigner": false, "isOptional": true, "docs": ["Token record account"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "argumentValueNode", "name": "tokenStandard" }, "value": { "kind": "enumValueNode", "variant": "programmableNonFungible", "enum": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "tokenRecord" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "editionMint" } }, { "kind": "pdaSeedValueNode", "name": "token", "value": { "kind": "accountValueNode", "name": "editionTokenAccount" } } ] } } }, { "kind": "instructionAccountNode", "name": "masterEdition", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [ "Master Record Edition V2 (pda of ['metadata', program id, master metadata mint id, 'edition'])" ], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "argumentValueNode", "name": "masterEditionMint" } } ] } }, { "kind": "instructionAccountNode", "name": "editionMarkerPda", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [ "Edition pda to mark creation - will be checked for pre-existence. (pda of ['metadata', program id, master metadata mint id, 'edition', edition_number]) where edition_number is NOT the edition number you pass in args but actually edition_number = floor(edition/EDITION_MARKER_BIT_SIZE)." ], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "argumentValueNode", "name": "tokenStandard" }, "value": { "kind": "enumValueNode", "variant": "programmableNonFungible", "enum": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "editionMarkerV2" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "argumentValueNode", "name": "masterEditionMint" } } ] }, "ifFalse": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "editionMarkerFromEditionNumber" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "argumentValueNode", "name": "masterEditionMint" } }, { "kind": "pdaSeedValueNode", "name": "editionNumber", "value": { "kind": "argumentValueNode", "name": "editionNumber" } } ] } } }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["payer"], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "masterTokenAccountOwner", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["owner of token account containing master token"], "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "holderDelegateRecord" }, "ifFalse": { "kind": "identityValueNode" } } }, { "kind": "instructionAccountNode", "name": "masterTokenAccount", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["token account containing token from master metadata mint"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "argumentValueNode", "name": "masterEditionMint" } }, { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "accountValueNode", "name": "masterTokenAccountOwner" } } ] } }, { "kind": "instructionAccountNode", "name": "masterMetadata", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Master record metadata account"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "argumentValueNode", "name": "masterEditionMint" } } ] } }, { "kind": "instructionAccountNode", "name": "updateAuthority", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The update authority of the master edition."], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "splTokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Token program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } }, { "kind": "instructionAccountNode", "name": "splAtaProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["SPL Associated Token Account program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", "identifier": "splAssociatedToken" } }, { "kind": "instructionAccountNode", "name": "sysvarInstructions", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar account"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "holderDelegateRecord", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["The Delegate Record authorizing escrowless edition printing"] }, { "kind": "instructionAccountNode", "name": "delegate", "isWritable": false, "isSigner": true, "isOptional": true, "docs": ["The authority printing the edition for a delegated print"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 55 } }, { "kind": "instructionArgumentNode", "name": "printV2Discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } }, { "kind": "instructionArgumentNode", "name": "editionNumber", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } } ], "extraArguments": [ { "kind": "instructionArgumentNode", "name": "masterEditionMint", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "instructionArgumentNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] } ] }, { "kind": "instructionNode", "name": "resize", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The metadata account of the digital asset"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "edition", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [ "The master edition or edition account of the digital asset, an uninitialized account for fungible assets" ], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Mint of token asset"] }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": "either", "isOptional": false, "docs": [ "The recipient of the excess rent and authority if the authority account is not present" ], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": true, "docs": [ "Owner of the asset for (p)NFTs, or mint authority for fungible assets, if different from the payer" ] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Token or Associated Token account"] }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 56 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "closeAccounts", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Metadata (pda of ['metadata', program id, mint id])"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "metadata" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "edition", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Edition of the asset"], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "masterEdition" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Mint of token asset"] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Authority to close ownerless accounts"], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "destination", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The destination account that will receive the rent."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 57 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] } ], "definedTypes": [ { "kind": "definedTypeNode", "name": "setCollectionSizeArgs", "docs": [], "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "size", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } } ] } }, { "kind": "definedTypeNode", "name": "mintNewEditionFromMasterEditionViaTokenArgs", "docs": [], "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "edition", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } } ] } }, { "kind": "definedTypeNode", "name": "authorizationData", "docs": [], "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "payload", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "payload" } } ] } }, { "kind": "definedTypeNode", "name": "collection", "docs": [], "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "verified", "docs": [], "type": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "key", "docs": [], "type": { "kind": "publicKeyTypeNode" } } ] } }, { "kind": "definedTypeNode", "name": "creator", "docs": [], "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "address", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "verified", "docs": [], "type": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "share", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } ] } }, { "kind": "definedTypeNode", "name": "data", "docs": [], "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "name", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "symbol", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "uri", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "sellerFeeBasisPoints", "docs": [], "type": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "creators", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "arrayTypeNode", "item": { "kind": "definedTypeLinkNode", "name": "creator" }, "count": { "kind": "prefixedCountNode", "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } } ] } }, { "kind": "definedTypeNode", "name": "dataV2", "docs": [], "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "name", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "symbol", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "uri", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "sellerFeeBasisPoints", "docs": [], "type": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "creators", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "arrayTypeNode", "item": { "kind": "definedTypeLinkNode", "name": "creator" }, "count": { "kind": "prefixedCountNode", "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "collection", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "collection" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "uses", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "uses" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } } ] } }, { "kind": "definedTypeNode", "name": "reservation", "docs": [], "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "address", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "spotsRemaining", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "totalSpots", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } } ] } }, { "kind": "definedTypeNode", "name": "reservationV1", "docs": [], "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "address", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "spotsRemaining", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "totalSpots", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } ] } }, { "kind": "definedTypeNode", "name": "seedsVec", "docs": [], "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "seeds", "docs": [], "type": { "kind": "arrayTypeNode", "item": { "kind": "sizePrefixTypeNode", "type": { "kind": "bytesTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } }, "count": { "kind": "prefixedCountNode", "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } } } ] } }, { "kind": "definedTypeNode", "name": "proofInfo", "docs": [], "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "proof", "docs": [], "type": { "kind": "arrayTypeNode", "item": { "kind": "fixedSizeTypeNode", "size": 32, "type": { "kind": "bytesTypeNode" } }, "count": { "kind": "prefixedCountNode", "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } } } ] } }, { "kind": "definedTypeNode", "name": "payload", "docs": [], "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "map", "docs": [], "type": { "kind": "mapTypeNode", "key": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } }, "value": { "kind": "definedTypeLinkNode", "name": "payloadType" }, "count": { "kind": "prefixedCountNode", "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } } } ] } }, { "kind": "definedTypeNode", "name": "uses", "docs": [], "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "useMethod", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "useMethod" } }, { "kind": "structFieldTypeNode", "name": "remaining", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "total", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } } ] } }, { "kind": "definedTypeNode", "name": "burnArgs", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumStructVariantTypeNode", "name": "v1", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "amount", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } } ] } } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "delegateArgs", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumStructVariantTypeNode", "name": "collectionV1", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ] } }, { "kind": "enumStructVariantTypeNode", "name": "saleV1", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "amount", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } }, { "kind": "structFieldTypeNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ] } }, { "kind": "enumStructVariantTypeNode", "name": "transferV1", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "amount", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } }, { "kind": "structFieldTypeNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ] } }, { "kind": "enumStructVariantTypeNode", "name": "dataV1", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ] } }, { "kind": "enumStructVariantTypeNode", "name": "utilityV1", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "amount", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } }, { "kind": "structFieldTypeNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ] } }, { "kind": "enumStructVariantTypeNode", "name": "stakingV1", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "amount", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } }, { "kind": "structFieldTypeNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ] } }, { "kind": "enumStructVariantTypeNode", "name": "standardV1", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "amount", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } } ] } }, { "kind": "enumStructVariantTypeNode", "name": "lockedTransferV1", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "amount", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } }, { "kind": "structFieldTypeNode", "name": "lockedAddress", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ] } }, { "kind": "enumStructVariantTypeNode", "name": "programmableConfigV1", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ] } }, { "kind": "enumStructVariantTypeNode", "name": "authorityItemV1", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ] } }, { "kind": "enumStructVariantTypeNode", "name": "dataItemV1", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ] } }, { "kind": "enumStructVariantTypeNode", "name": "collectionItemV1", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ] } }, { "kind": "enumStructVariantTypeNode", "name": "programmableConfigItemV1", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ] } }, { "kind": "enumStructVariantTypeNode", "name": "printDelegateV1", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ] } } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "revokeArgs", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumEmptyVariantTypeNode", "name": "collectionV1" }, { "kind": "enumEmptyVariantTypeNode", "name": "saleV1" }, { "kind": "enumEmptyVariantTypeNode", "name": "transferV1" }, { "kind": "enumEmptyVariantTypeNode", "name": "dataV1" }, { "kind": "enumEmptyVariantTypeNode", "name": "utilityV1" }, { "kind": "enumEmptyVariantTypeNode", "name": "stakingV1" }, { "kind": "enumEmptyVariantTypeNode", "name": "standardV1" }, { "kind": "enumEmptyVariantTypeNode", "name": "lockedTransferV1" }, { "kind": "enumEmptyVariantTypeNode", "name": "programmableConfigV1" }, { "kind": "enumEmptyVariantTypeNode", "name": "migrationV1" }, { "kind": "enumEmptyVariantTypeNode", "name": "authorityItemV1" }, { "kind": "enumEmptyVariantTypeNode", "name": "dataItemV1" }, { "kind": "enumEmptyVariantTypeNode", "name": "collectionItemV1" }, { "kind": "enumEmptyVariantTypeNode", "name": "programmableConfigItemV1" }, { "kind": "enumEmptyVariantTypeNode", "name": "printDelegateV1" } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "metadataDelegateRole", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumEmptyVariantTypeNode", "name": "authorityItem" }, { "kind": "enumEmptyVariantTypeNode", "name": "collection" }, { "kind": "enumEmptyVariantTypeNode", "name": "use" }, { "kind": "enumEmptyVariantTypeNode", "name": "data" }, { "kind": "enumEmptyVariantTypeNode", "name": "programmableConfig" }, { "kind": "enumEmptyVariantTypeNode", "name": "dataItem" }, { "kind": "enumEmptyVariantTypeNode", "name": "collectionItem" }, { "kind": "enumEmptyVariantTypeNode", "name": "programmableConfigItem" } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "holderDelegateRole", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumEmptyVariantTypeNode", "name": "printDelegate" } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "createArgs", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumStructVariantTypeNode", "name": "v1", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "name", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "symbol", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } }, "defaultValue": { "kind": "stringValueNode", "string": "" } }, { "kind": "structFieldTypeNode", "name": "uri", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "sellerFeeBasisPoints", "docs": [], "type": { "kind": "amountTypeNode", "decimals": 2, "unit": "%", "number": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "creators", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "arrayTypeNode", "item": { "kind": "definedTypeLinkNode", "name": "creator" }, "count": { "kind": "prefixedCountNode", "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "primarySaleHappened", "docs": [], "type": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "booleanValueNode", "boolean": false } }, { "kind": "structFieldTypeNode", "name": "isMutable", "docs": [], "type": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "booleanValueNode", "boolean": true } }, { "kind": "structFieldTypeNode", "name": "tokenStandard", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "tokenStandard" } }, { "kind": "structFieldTypeNode", "name": "collection", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "collection" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "structFieldTypeNode", "name": "uses", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "uses" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "structFieldTypeNode", "name": "collectionDetails", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "collectionDetails" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "structFieldTypeNode", "name": "ruleSet", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "publicKeyTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "structFieldTypeNode", "name": "decimals", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "structFieldTypeNode", "name": "printSupply", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "printSupply" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ] } } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "mintArgs", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumStructVariantTypeNode", "name": "v1", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "amount", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } }, { "kind": "structFieldTypeNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ] } } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "transferArgs", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumStructVariantTypeNode", "name": "v1", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "amount", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } }, { "kind": "structFieldTypeNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ] } } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "updateArgs", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumStructVariantTypeNode", "name": "v1", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "newUpdateAuthority", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "publicKeyTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "structFieldTypeNode", "name": "data", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "data" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "structFieldTypeNode", "name": "primarySaleHappened", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "structFieldTypeNode", "name": "isMutable", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "structFieldTypeNode", "name": "collection", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "collectionToggle" }, "defaultValue": { "kind": "enumValueNode", "variant": "none", "enum": { "kind": "definedTypeLinkNode", "name": "collectionToggle" } } }, { "kind": "structFieldTypeNode", "name": "collectionDetails", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "collectionDetailsToggle" }, "defaultValue": { "kind": "enumValueNode", "variant": "none", "enum": { "kind": "definedTypeLinkNode", "name": "collectionDetailsToggle" } } }, { "kind": "structFieldTypeNode", "name": "uses", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "usesToggle" }, "defaultValue": { "kind": "enumValueNode", "variant": "none", "enum": { "kind": "definedTypeLinkNode", "name": "usesToggle" } } }, { "kind": "structFieldTypeNode", "name": "ruleSet", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "ruleSetToggle" }, "defaultValue": { "kind": "enumValueNode", "variant": "none", "enum": { "kind": "definedTypeLinkNode", "name": "ruleSetToggle" } } }, { "kind": "structFieldTypeNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ] } }, { "kind": "enumStructVariantTypeNode", "name": "asUpdateAuthorityV2", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "newUpdateAuthority", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "publicKeyTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "structFieldTypeNode", "name": "data", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "data" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "structFieldTypeNode", "name": "primarySaleHappened", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "structFieldTypeNode", "name": "isMutable", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "structFieldTypeNode", "name": "collection", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "collectionToggle" }, "defaultValue": { "kind": "enumValueNode", "variant": "none", "enum": { "kind": "definedTypeLinkNode", "name": "collectionToggle" } } }, { "kind": "structFieldTypeNode", "name": "collectionDetails", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "collectionDetailsToggle" }, "defaultValue": { "kind": "enumValueNode", "variant": "none", "enum": { "kind": "definedTypeLinkNode", "name": "collectionDetailsToggle" } } }, { "kind": "structFieldTypeNode", "name": "uses", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "usesToggle" }, "defaultValue": { "kind": "enumValueNode", "variant": "none", "enum": { "kind": "definedTypeLinkNode", "name": "usesToggle" } } }, { "kind": "structFieldTypeNode", "name": "ruleSet", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "ruleSetToggle" }, "defaultValue": { "kind": "enumValueNode", "variant": "none", "enum": { "kind": "definedTypeLinkNode", "name": "ruleSetToggle" } } }, { "kind": "structFieldTypeNode", "name": "tokenStandard", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "tokenStandard" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "structFieldTypeNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ] } }, { "kind": "enumStructVariantTypeNode", "name": "asAuthorityItemDelegateV2", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "newUpdateAuthority", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "publicKeyTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "structFieldTypeNode", "name": "primarySaleHappened", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "structFieldTypeNode", "name": "isMutable", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "structFieldTypeNode", "name": "tokenStandard", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "tokenStandard" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "structFieldTypeNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ] } }, { "kind": "enumStructVariantTypeNode", "name": "asCollectionDelegateV2", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "collection", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "collectionToggle" }, "defaultValue": { "kind": "enumValueNode", "variant": "none", "enum": { "kind": "definedTypeLinkNode", "name": "collectionToggle" } } }, { "kind": "structFieldTypeNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ] } }, { "kind": "enumStructVariantTypeNode", "name": "asDataDelegateV2", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "data", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "data" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "structFieldTypeNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ] } }, { "kind": "enumStructVariantTypeNode", "name": "asProgrammableConfigDelegateV2", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "ruleSet", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "ruleSetToggle" }, "defaultValue": { "kind": "enumValueNode", "variant": "none", "enum": { "kind": "definedTypeLinkNode", "name": "ruleSetToggle" } } }, { "kind": "structFieldTypeNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ] } }, { "kind": "enumStructVariantTypeNode", "name": "asDataItemDelegateV2", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "data", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "data" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "structFieldTypeNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ] } }, { "kind": "enumStructVariantTypeNode", "name": "asCollectionItemDelegateV2", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "collection", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "collectionToggle" }, "defaultValue": { "kind": "enumValueNode", "variant": "none", "enum": { "kind": "definedTypeLinkNode", "name": "collectionToggle" } } }, { "kind": "structFieldTypeNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ] } }, { "kind": "enumStructVariantTypeNode", "name": "asProgrammableConfigItemDelegateV2", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "ruleSet", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "ruleSetToggle" }, "defaultValue": { "kind": "enumValueNode", "variant": "none", "enum": { "kind": "definedTypeLinkNode", "name": "ruleSetToggle" } } }, { "kind": "structFieldTypeNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ] } } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "collectionToggle", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumEmptyVariantTypeNode", "name": "none" }, { "kind": "enumEmptyVariantTypeNode", "name": "clear" }, { "kind": "enumTupleVariantTypeNode", "name": "set", "tuple": { "kind": "tupleTypeNode", "items": [ { "kind": "definedTypeLinkNode", "name": "collection" } ] } } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "usesToggle", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumEmptyVariantTypeNode", "name": "none" }, { "kind": "enumEmptyVariantTypeNode", "name": "clear" }, { "kind": "enumTupleVariantTypeNode", "name": "set", "tuple": { "kind": "tupleTypeNode", "items": [ { "kind": "definedTypeLinkNode", "name": "uses" } ] } } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "collectionDetailsToggle", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumEmptyVariantTypeNode", "name": "none" }, { "kind": "enumEmptyVariantTypeNode", "name": "clear" }, { "kind": "enumTupleVariantTypeNode", "name": "set", "tuple": { "kind": "tupleTypeNode", "items": [ { "kind": "definedTypeLinkNode", "name": "collectionDetails" } ] } } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "ruleSetToggle", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumEmptyVariantTypeNode", "name": "none" }, { "kind": "enumEmptyVariantTypeNode", "name": "clear" }, { "kind": "enumTupleVariantTypeNode", "name": "set", "tuple": { "kind": "tupleTypeNode", "items": [ { "kind": "publicKeyTypeNode" } ] } } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "printArgs", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumStructVariantTypeNode", "name": "v1", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "edition", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } } ] } }, { "kind": "enumStructVariantTypeNode", "name": "v2", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "edition", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } } ] } } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "lockArgs", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumStructVariantTypeNode", "name": "v1", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ] } } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "unlockArgs", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumStructVariantTypeNode", "name": "v1", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ] } } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "useArgs", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumStructVariantTypeNode", "name": "v1", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "authorizationData", "defaultValueStrategy": "optional", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "definedTypeLinkNode", "name": "authorizationData" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ] } } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "verificationArgs", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumEmptyVariantTypeNode", "name": "creatorV1" }, { "kind": "enumEmptyVariantTypeNode", "name": "collectionV1" } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "tokenStandard", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumEmptyVariantTypeNode", "name": "nonFungible" }, { "kind": "enumEmptyVariantTypeNode", "name": "fungibleAsset" }, { "kind": "enumEmptyVariantTypeNode", "name": "fungible" }, { "kind": "enumEmptyVariantTypeNode", "name": "nonFungibleEdition" }, { "kind": "enumEmptyVariantTypeNode", "name": "programmableNonFungible" }, { "kind": "enumEmptyVariantTypeNode", "name": "programmableNonFungibleEdition" } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "key", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumEmptyVariantTypeNode", "name": "uninitialized" }, { "kind": "enumEmptyVariantTypeNode", "name": "editionV1" }, { "kind": "enumEmptyVariantTypeNode", "name": "masterEditionV1" }, { "kind": "enumEmptyVariantTypeNode", "name": "reservationListV1" }, { "kind": "enumEmptyVariantTypeNode", "name": "metadataV1" }, { "kind": "enumEmptyVariantTypeNode", "name": "reservationListV2" }, { "kind": "enumEmptyVariantTypeNode", "name": "masterEditionV2" }, { "kind": "enumEmptyVariantTypeNode", "name": "editionMarker" }, { "kind": "enumEmptyVariantTypeNode", "name": "useAuthorityRecord" }, { "kind": "enumEmptyVariantTypeNode", "name": "collectionAuthorityRecord" }, { "kind": "enumEmptyVariantTypeNode", "name": "tokenOwnedEscrow" }, { "kind": "enumEmptyVariantTypeNode", "name": "tokenRecord" }, { "kind": "enumEmptyVariantTypeNode", "name": "metadataDelegate" }, { "kind": "enumEmptyVariantTypeNode", "name": "editionMarkerV2" }, { "kind": "enumEmptyVariantTypeNode", "name": "holderDelegate" } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "collectionDetails", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumStructVariantTypeNode", "name": "v1", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "size", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } } ] } }, { "kind": "enumStructVariantTypeNode", "name": "v2", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "padding", "docs": [], "type": { "kind": "fixedSizeTypeNode", "size": 8, "type": { "kind": "bytesTypeNode" } } } ] } } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "escrowAuthority", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumEmptyVariantTypeNode", "name": "tokenOwner" }, { "kind": "enumTupleVariantTypeNode", "name": "creator", "tuple": { "kind": "tupleTypeNode", "items": [ { "kind": "publicKeyTypeNode" } ] } } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "printSupply", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumEmptyVariantTypeNode", "name": "zero" }, { "kind": "enumTupleVariantTypeNode", "name": "limited", "tuple": { "kind": "tupleTypeNode", "items": [ { "kind": "numberTypeNode", "format": "u64", "endian": "le" } ] } }, { "kind": "enumEmptyVariantTypeNode", "name": "unlimited" } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "programmableConfig", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumStructVariantTypeNode", "name": "v1", "struct": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "ruleSet", "docs": [], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "publicKeyTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } } ] } } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "migrationType", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumEmptyVariantTypeNode", "name": "collectionV1" }, { "kind": "enumEmptyVariantTypeNode", "name": "programmableV1" } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "tokenState", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumEmptyVariantTypeNode", "name": "unlocked" }, { "kind": "enumEmptyVariantTypeNode", "name": "locked" }, { "kind": "enumEmptyVariantTypeNode", "name": "listed" } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "tokenDelegateRole", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumEmptyVariantTypeNode", "name": "sale" }, { "kind": "enumEmptyVariantTypeNode", "name": "transfer" }, { "kind": "enumEmptyVariantTypeNode", "name": "utility" }, { "kind": "enumEmptyVariantTypeNode", "name": "staking" }, { "kind": "enumEmptyVariantTypeNode", "name": "standard" }, { "kind": "enumEmptyVariantTypeNode", "name": "lockedTransfer" }, { "kind": "enumEmptyVariantTypeNode", "name": "migration" } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "authorityType", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumEmptyVariantTypeNode", "name": "none" }, { "kind": "enumEmptyVariantTypeNode", "name": "metadata" }, { "kind": "enumEmptyVariantTypeNode", "name": "holder" }, { "kind": "enumEmptyVariantTypeNode", "name": "metadataDelegate" }, { "kind": "enumEmptyVariantTypeNode", "name": "tokenDelegate" } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "payloadKey", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumEmptyVariantTypeNode", "name": "amount" }, { "kind": "enumEmptyVariantTypeNode", "name": "authority" }, { "kind": "enumEmptyVariantTypeNode", "name": "authoritySeeds" }, { "kind": "enumEmptyVariantTypeNode", "name": "delegate" }, { "kind": "enumEmptyVariantTypeNode", "name": "delegateSeeds" }, { "kind": "enumEmptyVariantTypeNode", "name": "destination" }, { "kind": "enumEmptyVariantTypeNode", "name": "destinationSeeds" }, { "kind": "enumEmptyVariantTypeNode", "name": "holder" }, { "kind": "enumEmptyVariantTypeNode", "name": "source" }, { "kind": "enumEmptyVariantTypeNode", "name": "sourceSeeds" } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "payloadType", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumTupleVariantTypeNode", "name": "pubkey", "tuple": { "kind": "tupleTypeNode", "items": [ { "kind": "publicKeyTypeNode" } ] } }, { "kind": "enumTupleVariantTypeNode", "name": "seeds", "tuple": { "kind": "tupleTypeNode", "items": [ { "kind": "definedTypeLinkNode", "name": "seedsVec" } ] } }, { "kind": "enumTupleVariantTypeNode", "name": "merkleProof", "tuple": { "kind": "tupleTypeNode", "items": [ { "kind": "definedTypeLinkNode", "name": "proofInfo" } ] } }, { "kind": "enumTupleVariantTypeNode", "name": "number", "tuple": { "kind": "tupleTypeNode", "items": [ { "kind": "numberTypeNode", "format": "u64", "endian": "le" } ] } } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "useMethod", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumEmptyVariantTypeNode", "name": "burn" }, { "kind": "enumEmptyVariantTypeNode", "name": "multiple" }, { "kind": "enumEmptyVariantTypeNode", "name": "single" } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } } ], "pdas": [ { "kind": "pdaNode", "name": "metadata", "docs": [], "seeds": [ { "kind": "constantPdaSeedNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "value": { "kind": "stringValueNode", "string": "metadata" } }, { "kind": "constantPdaSeedNode", "type": { "kind": "publicKeyTypeNode" }, "value": { "kind": "programIdValueNode" } }, { "kind": "variablePdaSeedNode", "name": "mint", "docs": ["The address of the mint account"], "type": { "kind": "publicKeyTypeNode" } } ] }, { "kind": "pdaNode", "name": "deprecatedMasterEditionV1", "docs": [], "seeds": [ { "kind": "constantPdaSeedNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "value": { "kind": "stringValueNode", "string": "metadata" } }, { "kind": "constantPdaSeedNode", "type": { "kind": "publicKeyTypeNode" }, "value": { "kind": "programIdValueNode" } }, { "kind": "variablePdaSeedNode", "name": "mint", "docs": ["The address of the mint account"], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "constantPdaSeedNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "value": { "kind": "stringValueNode", "string": "edition" } } ] }, { "kind": "pdaNode", "name": "masterEdition", "docs": [], "seeds": [ { "kind": "constantPdaSeedNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "value": { "kind": "stringValueNode", "string": "metadata" } }, { "kind": "constantPdaSeedNode", "type": { "kind": "publicKeyTypeNode" }, "value": { "kind": "programIdValueNode" } }, { "kind": "variablePdaSeedNode", "name": "mint", "docs": ["The address of the mint account"], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "constantPdaSeedNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "value": { "kind": "stringValueNode", "string": "edition" } } ] }, { "kind": "pdaNode", "name": "editionMarker", "docs": [], "seeds": [ { "kind": "constantPdaSeedNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "value": { "kind": "stringValueNode", "string": "metadata" } }, { "kind": "constantPdaSeedNode", "type": { "kind": "publicKeyTypeNode" }, "value": { "kind": "programIdValueNode" } }, { "kind": "variablePdaSeedNode", "name": "mint", "docs": ["The address of the mint account"], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "constantPdaSeedNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "value": { "kind": "stringValueNode", "string": "edition" } }, { "kind": "variablePdaSeedNode", "name": "editionMarker", "docs": ["The floor of the edition number divided by 248 as a string. I.e. ⌊edition/248⌋."], "type": { "kind": "stringTypeNode", "encoding": "utf8" } } ] }, { "kind": "pdaNode", "name": "editionMarkerV2", "docs": [], "seeds": [ { "kind": "constantPdaSeedNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "value": { "kind": "stringValueNode", "string": "metadata" } }, { "kind": "constantPdaSeedNode", "type": { "kind": "publicKeyTypeNode" }, "value": { "kind": "programIdValueNode" } }, { "kind": "variablePdaSeedNode", "name": "mint", "docs": ["The address of the mint account"], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "constantPdaSeedNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "value": { "kind": "stringValueNode", "string": "edition" } }, { "kind": "constantPdaSeedNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "value": { "kind": "stringValueNode", "string": "marker" } } ] }, { "kind": "pdaNode", "name": "tokenRecord", "docs": [], "seeds": [ { "kind": "constantPdaSeedNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "value": { "kind": "stringValueNode", "string": "metadata" } }, { "kind": "constantPdaSeedNode", "type": { "kind": "publicKeyTypeNode" }, "value": { "kind": "programIdValueNode" } }, { "kind": "variablePdaSeedNode", "name": "mint", "docs": ["The address of the mint account"], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "constantPdaSeedNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "value": { "kind": "stringValueNode", "string": "token_record" } }, { "kind": "variablePdaSeedNode", "name": "token", "docs": ["The address of the token account (ata or not)"], "type": { "kind": "publicKeyTypeNode" } } ] }, { "kind": "pdaNode", "name": "metadataDelegateRecord", "docs": [], "seeds": [ { "kind": "constantPdaSeedNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "value": { "kind": "stringValueNode", "string": "metadata" } }, { "kind": "constantPdaSeedNode", "type": { "kind": "publicKeyTypeNode" }, "value": { "kind": "programIdValueNode" } }, { "kind": "variablePdaSeedNode", "name": "mint", "docs": ["The address of the mint account"], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "variablePdaSeedNode", "name": "delegateRole", "docs": ["The role of the metadata delegate"], "type": { "kind": "definedTypeLinkNode", "name": "metadataDelegateRoleSeed" } }, { "kind": "variablePdaSeedNode", "name": "updateAuthority", "docs": ["The address of the metadata's update authority"], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "variablePdaSeedNode", "name": "delegate", "docs": ["The address of the delegate authority"], "type": { "kind": "publicKeyTypeNode" } } ] }, { "kind": "pdaNode", "name": "collectionAuthorityRecord", "docs": [], "seeds": [ { "kind": "constantPdaSeedNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "value": { "kind": "stringValueNode", "string": "metadata" } }, { "kind": "constantPdaSeedNode", "type": { "kind": "publicKeyTypeNode" }, "value": { "kind": "programIdValueNode" } }, { "kind": "variablePdaSeedNode", "name": "mint", "docs": ["The address of the mint account"], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "constantPdaSeedNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "value": { "kind": "stringValueNode", "string": "collection_authority" } }, { "kind": "variablePdaSeedNode", "name": "collectionAuthority", "docs": ["The address of the collection authority"], "type": { "kind": "publicKeyTypeNode" } } ] }, { "kind": "pdaNode", "name": "holderDelegateRecord", "docs": [], "seeds": [ { "kind": "constantPdaSeedNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "value": { "kind": "stringValueNode", "string": "metadata" } }, { "kind": "constantPdaSeedNode", "type": { "kind": "publicKeyTypeNode" }, "value": { "kind": "programIdValueNode" } }, { "kind": "variablePdaSeedNode", "name": "mint", "docs": ["The address of the mint account"], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "variablePdaSeedNode", "name": "delegateRole", "docs": ["The role of the holder delegate"], "type": { "kind": "definedTypeLinkNode", "name": "holderDelegateRoleSeed" } }, { "kind": "variablePdaSeedNode", "name": "owner", "docs": ["The address of the owner of the token"], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "variablePdaSeedNode", "name": "delegate", "docs": ["The address of the delegate authority"], "type": { "kind": "publicKeyTypeNode" } } ] }, { "kind": "pdaNode", "name": "useAuthorityRecord", "docs": [], "seeds": [ { "kind": "constantPdaSeedNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "value": { "kind": "stringValueNode", "string": "metadata" } }, { "kind": "constantPdaSeedNode", "type": { "kind": "publicKeyTypeNode" }, "value": { "kind": "programIdValueNode" } }, { "kind": "variablePdaSeedNode", "name": "mint", "docs": ["The address of the mint account"], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "constantPdaSeedNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "value": { "kind": "stringValueNode", "string": "user" } }, { "kind": "variablePdaSeedNode", "name": "useAuthority", "docs": ["The address of the use authority"], "type": { "kind": "publicKeyTypeNode" } } ] } ], "errors": [ { "kind": "errorNode", "name": "instructionUnpackError", "code": 0, "message": "", "docs": ["InstructionUnpackError"] }, { "kind": "errorNode", "name": "instructionPackError", "code": 1, "message": "", "docs": ["InstructionPackError"] }, { "kind": "errorNode", "name": "notRentExempt", "code": 2, "message": "Lamport balance below rent-exempt threshold", "docs": ["NotRentExempt: Lamport balance below rent-exempt threshold"] }, { "kind": "errorNode", "name": "alreadyInitialized", "code": 3, "message": "Already initialized", "docs": ["AlreadyInitialized: Already initialized"] }, { "kind": "errorNode", "name": "uninitialized", "code": 4, "message": "Uninitialized", "docs": ["Uninitialized: Uninitialized"] }, { "kind": "errorNode", "name": "invalidMetadataKey", "code": 5, "message": " Metadata's key must match seed of ['metadata', program id, mint] provided", "docs": [ "InvalidMetadataKey: Metadata's key must match seed of ['metadata', program id, mint] provided" ] }, { "kind": "errorNode", "name": "invalidEditionKey", "code": 6, "message": "Edition's key must match seed of ['metadata', program id, name, 'edition'] provided", "docs": [ "InvalidEditionKey: Edition's key must match seed of ['metadata', program id, name, 'edition'] provided" ] }, { "kind": "errorNode", "name": "updateAuthorityIncorrect", "code": 7, "message": "Update Authority given does not match", "docs": ["UpdateAuthorityIncorrect: Update Authority given does not match"] }, { "kind": "errorNode", "name": "updateAuthorityIsNotSigner", "code": 8, "message": "Update Authority needs to be signer to update metadata", "docs": ["UpdateAuthorityIsNotSigner: Update Authority needs to be signer to update metadata"] }, { "kind": "errorNode", "name": "notMintAuthority", "code": 9, "message": "You must be the mint authority and signer on this transaction", "docs": ["NotMintAuthority: You must be the mint authority and signer on this transaction"] }, { "kind": "errorNode", "name": "invalidMintAuthority", "code": 10, "message": "Mint authority provided does not match the authority on the mint", "docs": ["InvalidMintAuthority: Mint authority provided does not match the authority on the mint"] }, { "kind": "errorNode", "name": "nameTooLong", "code": 11, "message": "Name too long", "docs": ["NameTooLong: Name too long"] }, { "kind": "errorNode", "name": "symbolTooLong", "code": 12, "message": "Symbol too long", "docs": ["SymbolTooLong: Symbol too long"] }, { "kind": "errorNode", "name": "uriTooLong", "code": 13, "message": "URI too long", "docs": ["UriTooLong: URI too long"] }, { "kind": "errorNode", "name": "updateAuthorityMustBeEqualToMetadataAuthorityAndSigner", "code": 14, "message": "", "docs": ["UpdateAuthorityMustBeEqualToMetadataAuthorityAndSigner"] }, { "kind": "errorNode", "name": "mintMismatch", "code": 15, "message": "Mint given does not match mint on Metadata", "docs": ["MintMismatch: Mint given does not match mint on Metadata"] }, { "kind": "errorNode", "name": "editionsMustHaveExactlyOneToken", "code": 16, "message": "Editions must have exactly one token", "docs": ["EditionsMustHaveExactlyOneToken: Editions must have exactly one token"] }, { "kind": "errorNode", "name": "maxEditionsMintedAlready", "code": 17, "message": "", "docs": ["MaxEditionsMintedAlready"] }, { "kind": "errorNode", "name": "tokenMintToFailed", "code": 18, "message": "", "docs": ["TokenMintToFailed"] }, { "kind": "errorNode", "name": "masterRecordMismatch", "code": 19, "message": "", "docs": ["MasterRecordMismatch"] }, { "kind": "errorNode", "name": "destinationMintMismatch", "code": 20, "message": "", "docs": ["DestinationMintMismatch"] }, { "kind": "errorNode", "name": "editionAlreadyMinted", "code": 21, "message": "", "docs": ["EditionAlreadyMinted"] }, { "kind": "errorNode", "name": "printingMintDecimalsShouldBeZero", "code": 22, "message": "", "docs": ["PrintingMintDecimalsShouldBeZero"] }, { "kind": "errorNode", "name": "oneTimePrintingAuthorizationMintDecimalsShouldBeZero", "code": 23, "message": "", "docs": ["OneTimePrintingAuthorizationMintDecimalsShouldBeZero"] }, { "kind": "errorNode", "name": "editionMintDecimalsShouldBeZero", "code": 24, "message": "EditionMintDecimalsShouldBeZero", "docs": ["EditionMintDecimalsShouldBeZero: EditionMintDecimalsShouldBeZero"] }, { "kind": "errorNode", "name": "tokenBurnFailed", "code": 25, "message": "", "docs": ["TokenBurnFailed"] }, { "kind": "errorNode", "name": "tokenAccountOneTimeAuthMintMismatch", "code": 26, "message": "", "docs": ["TokenAccountOneTimeAuthMintMismatch"] }, { "kind": "errorNode", "name": "derivedKeyInvalid", "code": 27, "message": "Derived key invalid", "docs": ["DerivedKeyInvalid: Derived key invalid"] }, { "kind": "errorNode", "name": "printingMintMismatch", "code": 28, "message": "The Printing mint does not match that on the master edition!", "docs": ["PrintingMintMismatch: The Printing mint does not match that on the master edition!"] }, { "kind": "errorNode", "name": "oneTimePrintingAuthMintMismatch", "code": 29, "message": "The One Time Printing Auth mint does not match that on the master edition!", "docs": [ "OneTimePrintingAuthMintMismatch: The One Time Printing Auth mint does not match that on the master edition!" ] }, { "kind": "errorNode", "name": "tokenAccountMintMismatch", "code": 30, "message": "The mint of the token account does not match the Printing mint!", "docs": ["TokenAccountMintMismatch: The mint of the token account does not match the Printing mint!"] }, { "kind": "errorNode", "name": "tokenAccountMintMismatchV2", "code": 31, "message": "The mint of the token account does not match the master metadata mint!", "docs": [ "TokenAccountMintMismatchV2: The mint of the token account does not match the master metadata mint!" ] }, { "kind": "errorNode", "name": "notEnoughTokens", "code": 32, "message": "Not enough tokens to mint a limited edition", "docs": ["NotEnoughTokens: Not enough tokens to mint a limited edition"] }, { "kind": "errorNode", "name": "printingMintAuthorizationAccountMismatch", "code": 33, "message": "", "docs": ["PrintingMintAuthorizationAccountMismatch"] }, { "kind": "errorNode", "name": "authorizationTokenAccountOwnerMismatch", "code": 34, "message": "", "docs": ["AuthorizationTokenAccountOwnerMismatch"] }, { "kind": "errorNode", "name": "disabled", "code": 35, "message": "", "docs": ["Disabled"] }, { "kind": "errorNode", "name": "creatorsTooLong", "code": 36, "message": "Creators list too long", "docs": ["CreatorsTooLong: Creators list too long"] }, { "kind": "errorNode", "name": "creatorsMustBeAtleastOne", "code": 37, "message": "Creators must be at least one if set", "docs": ["CreatorsMustBeAtleastOne: Creators must be at least one if set"] }, { "kind": "errorNode", "name": "mustBeOneOfCreators", "code": 38, "message": "", "docs": ["MustBeOneOfCreators"] }, { "kind": "errorNode", "name": "noCreatorsPresentOnMetadata", "code": 39, "message": "This metadata does not have creators", "docs": ["NoCreatorsPresentOnMetadata: This metadata does not have creators"] }, { "kind": "errorNode", "name": "creatorNotFound", "code": 40, "message": "This creator address was not found", "docs": ["CreatorNotFound: This creator address was not found"] }, { "kind": "errorNode", "name": "invalidBasisPoints", "code": 41, "message": "Basis points cannot be more than 10000", "docs": ["InvalidBasisPoints: Basis points cannot be more than 10000"] }, { "kind": "errorNode", "name": "primarySaleCanOnlyBeFlippedToTrue", "code": 42, "message": "Primary sale can only be flipped to true and is immutable", "docs": ["PrimarySaleCanOnlyBeFlippedToTrue: Primary sale can only be flipped to true and is immutable"] }, { "kind": "errorNode", "name": "ownerMismatch", "code": 43, "message": "Owner does not match that on the account given", "docs": ["OwnerMismatch: Owner does not match that on the account given"] }, { "kind": "errorNode", "name": "noBalanceInAccountForAuthorization", "code": 44, "message": "This account has no tokens to be used for authorization", "docs": ["NoBalanceInAccountForAuthorization: This account has no tokens to be used for authorization"] }, { "kind": "errorNode", "name": "shareTotalMustBe100", "code": 45, "message": "Share total must equal 100 for creator array", "docs": ["ShareTotalMustBe100: Share total must equal 100 for creator array"] }, { "kind": "errorNode", "name": "reservationExists", "code": 46, "message": "", "docs": ["ReservationExists"] }, { "kind": "errorNode", "name": "reservationDoesNotExist", "code": 47, "message": "", "docs": ["ReservationDoesNotExist"] }, { "kind": "errorNode", "name": "reservationNotSet", "code": 48, "message": "", "docs": ["ReservationNotSet"] }, { "kind": "errorNode", "name": "reservationAlreadyMade", "code": 49, "message": "", "docs": ["ReservationAlreadyMade"] }, { "kind": "errorNode", "name": "beyondMaxAddressSize", "code": 50, "message": "", "docs": ["BeyondMaxAddressSize"] }, { "kind": "errorNode", "name": "numericalOverflowError", "code": 51, "message": "NumericalOverflowError", "docs": ["NumericalOverflowError: NumericalOverflowError"] }, { "kind": "errorNode", "name": "reservationBreachesMaximumSupply", "code": 52, "message": "", "docs": ["ReservationBreachesMaximumSupply"] }, { "kind": "errorNode", "name": "addressNotInReservation", "code": 53, "message": "", "docs": ["AddressNotInReservation"] }, { "kind": "errorNode", "name": "cannotVerifyAnotherCreator", "code": 54, "message": "You cannot unilaterally verify another creator, they must sign", "docs": ["CannotVerifyAnotherCreator: You cannot unilaterally verify another creator, they must sign"] }, { "kind": "errorNode", "name": "cannotUnverifyAnotherCreator", "code": 55, "message": "You cannot unilaterally unverify another creator", "docs": ["CannotUnverifyAnotherCreator: You cannot unilaterally unverify another creator"] }, { "kind": "errorNode", "name": "spotMismatch", "code": 56, "message": "", "docs": ["SpotMismatch"] }, { "kind": "errorNode", "name": "incorrectOwner", "code": 57, "message": "Incorrect account owner", "docs": ["IncorrectOwner: Incorrect account owner"] }, { "kind": "errorNode", "name": "printingWouldBreachMaximumSupply", "code": 58, "message": "", "docs": ["PrintingWouldBreachMaximumSupply"] }, { "kind": "errorNode", "name": "dataIsImmutable", "code": 59, "message": "Data is immutable", "docs": ["DataIsImmutable: Data is immutable"] }, { "kind": "errorNode", "name": "duplicateCreatorAddress", "code": 60, "message": "No duplicate creator addresses", "docs": ["DuplicateCreatorAddress: No duplicate creator addresses"] }, { "kind": "errorNode", "name": "reservationSpotsRemainingShouldMatchTotalSpotsAtStart", "code": 61, "message": "", "docs": ["ReservationSpotsRemainingShouldMatchTotalSpotsAtStart"] }, { "kind": "errorNode", "name": "invalidTokenProgram", "code": 62, "message": "Invalid token program", "docs": ["InvalidTokenProgram: Invalid token program"] }, { "kind": "errorNode", "name": "dataTypeMismatch", "code": 63, "message": "Data type mismatch", "docs": ["DataTypeMismatch: Data type mismatch"] }, { "kind": "errorNode", "name": "beyondAlottedAddressSize", "code": 64, "message": "", "docs": ["BeyondAlottedAddressSize"] }, { "kind": "errorNode", "name": "reservationNotComplete", "code": 65, "message": "", "docs": ["ReservationNotComplete"] }, { "kind": "errorNode", "name": "triedToReplaceAnExistingReservation", "code": 66, "message": "", "docs": ["TriedToReplaceAnExistingReservation"] }, { "kind": "errorNode", "name": "invalidOperation", "code": 67, "message": "Invalid operation", "docs": ["InvalidOperation: Invalid operation"] }, { "kind": "errorNode", "name": "invalidOwner", "code": 68, "message": "Invalid Owner", "docs": ["InvalidOwner: Invalid Owner"] }, { "kind": "errorNode", "name": "printingMintSupplyMustBeZeroForConversion", "code": 69, "message": "Printing mint supply must be zero for conversion", "docs": ["PrintingMintSupplyMustBeZeroForConversion: Printing mint supply must be zero for conversion"] }, { "kind": "errorNode", "name": "oneTimeAuthMintSupplyMustBeZeroForConversion", "code": 70, "message": "One Time Auth mint supply must be zero for conversion", "docs": [ "OneTimeAuthMintSupplyMustBeZeroForConversion: One Time Auth mint supply must be zero for conversion" ] }, { "kind": "errorNode", "name": "invalidEditionIndex", "code": 71, "message": "You tried to insert one edition too many into an edition mark pda", "docs": ["InvalidEditionIndex: You tried to insert one edition too many into an edition mark pda"] }, { "kind": "errorNode", "name": "reservationArrayShouldBeSizeOne", "code": 72, "message": "", "docs": ["ReservationArrayShouldBeSizeOne"] }, { "kind": "errorNode", "name": "isMutableCanOnlyBeFlippedToFalse", "code": 73, "message": "Is Mutable can only be flipped to false", "docs": ["IsMutableCanOnlyBeFlippedToFalse: Is Mutable can only be flipped to false"] }, { "kind": "errorNode", "name": "collectionCannotBeVerifiedInThisInstruction", "code": 74, "message": "Collection cannot be verified in this instruction", "docs": [ "CollectionCannotBeVerifiedInThisInstruction: Collection cannot be verified in this instruction" ] }, { "kind": "errorNode", "name": "removed", "code": 75, "message": "This instruction was deprecated in a previous release and is now removed", "docs": ["Removed: This instruction was deprecated in a previous release and is now removed"] }, { "kind": "errorNode", "name": "mustBeBurned", "code": 76, "message": "", "docs": ["MustBeBurned"] }, { "kind": "errorNode", "name": "invalidUseMethod", "code": 77, "message": "This use method is invalid", "docs": ["InvalidUseMethod: This use method is invalid"] }, { "kind": "errorNode", "name": "cannotChangeUseMethodAfterFirstUse", "code": 78, "message": "Cannot Change Use Method after the first use", "docs": ["CannotChangeUseMethodAfterFirstUse: Cannot Change Use Method after the first use"] }, { "kind": "errorNode", "name": "cannotChangeUsesAfterFirstUse", "code": 79, "message": "Cannot Change Remaining or Available uses after the first use", "docs": ["CannotChangeUsesAfterFirstUse: Cannot Change Remaining or Available uses after the first use"] }, { "kind": "errorNode", "name": "collectionNotFound", "code": 80, "message": "Collection Not Found on Metadata", "docs": ["CollectionNotFound: Collection Not Found on Metadata"] }, { "kind": "errorNode", "name": "invalidCollectionUpdateAuthority", "code": 81, "message": "Collection Update Authority is invalid", "docs": ["InvalidCollectionUpdateAuthority: Collection Update Authority is invalid"] }, { "kind": "errorNode", "name": "collectionMustBeAUniqueMasterEdition", "code": 82, "message": "Collection Must Be a Unique Master Edition v2", "docs": ["CollectionMustBeAUniqueMasterEdition: Collection Must Be a Unique Master Edition v2"] }, { "kind": "errorNode", "name": "useAuthorityRecordAlreadyExists", "code": 83, "message": "The Use Authority Record Already Exists, to modify it Revoke, then Approve", "docs": [ "UseAuthorityRecordAlreadyExists: The Use Authority Record Already Exists, to modify it Revoke, then Approve" ] }, { "kind": "errorNode", "name": "useAuthorityRecordAlreadyRevoked", "code": 84, "message": "The Use Authority Record is empty or already revoked", "docs": ["UseAuthorityRecordAlreadyRevoked: The Use Authority Record is empty or already revoked"] }, { "kind": "errorNode", "name": "unusable", "code": 85, "message": "This token has no uses", "docs": ["Unusable: This token has no uses"] }, { "kind": "errorNode", "name": "notEnoughUses", "code": 86, "message": "There are not enough Uses left on this token.", "docs": ["NotEnoughUses: There are not enough Uses left on this token."] }, { "kind": "errorNode", "name": "collectionAuthorityRecordAlreadyExists", "code": 87, "message": "This Collection Authority Record Already Exists.", "docs": ["CollectionAuthorityRecordAlreadyExists: This Collection Authority Record Already Exists."] }, { "kind": "errorNode", "name": "collectionAuthorityDoesNotExist", "code": 88, "message": "This Collection Authority Record Does Not Exist.", "docs": ["CollectionAuthorityDoesNotExist: This Collection Authority Record Does Not Exist."] }, { "kind": "errorNode", "name": "invalidUseAuthorityRecord", "code": 89, "message": "This Use Authority Record is invalid.", "docs": ["InvalidUseAuthorityRecord: This Use Authority Record is invalid."] }, { "kind": "errorNode", "name": "invalidCollectionAuthorityRecord", "code": 90, "message": "", "docs": ["InvalidCollectionAuthorityRecord"] }, { "kind": "errorNode", "name": "invalidFreezeAuthority", "code": 91, "message": "Metadata does not match the freeze authority on the mint", "docs": ["InvalidFreezeAuthority: Metadata does not match the freeze authority on the mint"] }, { "kind": "errorNode", "name": "invalidDelegate", "code": 92, "message": "All tokens in this account have not been delegated to this user.", "docs": ["InvalidDelegate: All tokens in this account have not been delegated to this user."] }, { "kind": "errorNode", "name": "cannotAdjustVerifiedCreator", "code": 93, "message": "", "docs": ["CannotAdjustVerifiedCreator"] }, { "kind": "errorNode", "name": "cannotRemoveVerifiedCreator", "code": 94, "message": "Verified creators cannot be removed.", "docs": ["CannotRemoveVerifiedCreator: Verified creators cannot be removed."] }, { "kind": "errorNode", "name": "cannotWipeVerifiedCreators", "code": 95, "message": "", "docs": ["CannotWipeVerifiedCreators"] }, { "kind": "errorNode", "name": "notAllowedToChangeSellerFeeBasisPoints", "code": 96, "message": "", "docs": ["NotAllowedToChangeSellerFeeBasisPoints"] }, { "kind": "errorNode", "name": "editionOverrideCannotBeZero", "code": 97, "message": "Edition override cannot be zero", "docs": ["EditionOverrideCannotBeZero: Edition override cannot be zero"] }, { "kind": "errorNode", "name": "invalidUser", "code": 98, "message": "Invalid User", "docs": ["InvalidUser: Invalid User"] }, { "kind": "errorNode", "name": "revokeCollectionAuthoritySignerIncorrect", "code": 99, "message": "Revoke Collection Authority signer is incorrect", "docs": ["RevokeCollectionAuthoritySignerIncorrect: Revoke Collection Authority signer is incorrect"] }, { "kind": "errorNode", "name": "tokenCloseFailed", "code": 100, "message": "", "docs": ["TokenCloseFailed"] }, { "kind": "errorNode", "name": "unsizedCollection", "code": 101, "message": "Can't use this function on unsized collection", "docs": ["UnsizedCollection: Can't use this function on unsized collection"] }, { "kind": "errorNode", "name": "sizedCollection", "code": 102, "message": "Can't use this function on a sized collection", "docs": ["SizedCollection: Can't use this function on a sized collection"] }, { "kind": "errorNode", "name": "missingCollectionMetadata", "code": 103, "message": "Missing collection metadata account", "docs": ["MissingCollectionMetadata: Missing collection metadata account"] }, { "kind": "errorNode", "name": "notAMemberOfCollection", "code": 104, "message": "This NFT is not a member of the specified collection.", "docs": ["NotAMemberOfCollection: This NFT is not a member of the specified collection."] }, { "kind": "errorNode", "name": "notVerifiedMemberOfCollection", "code": 105, "message": "This NFT is not a verified member of the specified collection.", "docs": [ "NotVerifiedMemberOfCollection: This NFT is not a verified member of the specified collection." ] }, { "kind": "errorNode", "name": "notACollectionParent", "code": 106, "message": "This NFT is not a collection parent NFT.", "docs": ["NotACollectionParent: This NFT is not a collection parent NFT."] }, { "kind": "errorNode", "name": "couldNotDetermineTokenStandard", "code": 107, "message": "Could not determine a TokenStandard type.", "docs": ["CouldNotDetermineTokenStandard: Could not determine a TokenStandard type."] }, { "kind": "errorNode", "name": "missingEditionAccount", "code": 108, "message": "This mint account has an edition but none was provided.", "docs": ["MissingEditionAccount: This mint account has an edition but none was provided."] }, { "kind": "errorNode", "name": "notAMasterEdition", "code": 109, "message": "This edition is not a Master Edition", "docs": ["NotAMasterEdition: This edition is not a Master Edition"] }, { "kind": "errorNode", "name": "masterEditionHasPrints", "code": 110, "message": "This Master Edition has existing prints", "docs": ["MasterEditionHasPrints: This Master Edition has existing prints"] }, { "kind": "errorNode", "name": "borshDeserializationError", "code": 111, "message": "", "docs": ["BorshDeserializationError"] }, { "kind": "errorNode", "name": "cannotUpdateVerifiedCollection", "code": 112, "message": "Cannot update a verified collection in this command", "docs": ["CannotUpdateVerifiedCollection: Cannot update a verified collection in this command"] }, { "kind": "errorNode", "name": "collectionMasterEditionAccountInvalid", "code": 113, "message": "Edition account doesnt match collection ", "docs": ["CollectionMasterEditionAccountInvalid: Edition account doesnt match collection "] }, { "kind": "errorNode", "name": "alreadyVerified", "code": 114, "message": "Item is already verified.", "docs": ["AlreadyVerified: Item is already verified."] }, { "kind": "errorNode", "name": "alreadyUnverified", "code": 115, "message": "", "docs": ["AlreadyUnverified"] }, { "kind": "errorNode", "name": "notAPrintEdition", "code": 116, "message": "This edition is not a Print Edition", "docs": ["NotAPrintEdition: This edition is not a Print Edition"] }, { "kind": "errorNode", "name": "invalidMasterEdition", "code": 117, "message": "Invalid Master Edition", "docs": ["InvalidMasterEdition: Invalid Master Edition"] }, { "kind": "errorNode", "name": "invalidPrintEdition", "code": 118, "message": "Invalid Print Edition", "docs": ["InvalidPrintEdition: Invalid Print Edition"] }, { "kind": "errorNode", "name": "invalidEditionMarker", "code": 119, "message": "Invalid Edition Marker", "docs": ["InvalidEditionMarker: Invalid Edition Marker"] }, { "kind": "errorNode", "name": "reservationListDeprecated", "code": 120, "message": "Reservation List is Deprecated", "docs": ["ReservationListDeprecated: Reservation List is Deprecated"] }, { "kind": "errorNode", "name": "printEditionDoesNotMatchMasterEdition", "code": 121, "message": "Print Edition does not match Master Edition", "docs": ["PrintEditionDoesNotMatchMasterEdition: Print Edition does not match Master Edition"] }, { "kind": "errorNode", "name": "editionNumberGreaterThanMaxSupply", "code": 122, "message": "Edition Number greater than max supply", "docs": ["EditionNumberGreaterThanMaxSupply: Edition Number greater than max supply"] }, { "kind": "errorNode", "name": "mustUnverify", "code": 123, "message": "Must unverify before migrating collections.", "docs": ["MustUnverify: Must unverify before migrating collections."] }, { "kind": "errorNode", "name": "invalidEscrowBumpSeed", "code": 124, "message": "Invalid Escrow Account Bump Seed", "docs": ["InvalidEscrowBumpSeed: Invalid Escrow Account Bump Seed"] }, { "kind": "errorNode", "name": "mustBeEscrowAuthority", "code": 125, "message": "Must Escrow Authority", "docs": ["MustBeEscrowAuthority: Must Escrow Authority"] }, { "kind": "errorNode", "name": "invalidSystemProgram", "code": 126, "message": "Invalid System Program", "docs": ["InvalidSystemProgram: Invalid System Program"] }, { "kind": "errorNode", "name": "mustBeNonFungible", "code": 127, "message": "Must be a Non Fungible Token", "docs": ["MustBeNonFungible: Must be a Non Fungible Token"] }, { "kind": "errorNode", "name": "insufficientTokens", "code": 128, "message": "Insufficient tokens for transfer", "docs": ["InsufficientTokens: Insufficient tokens for transfer"] }, { "kind": "errorNode", "name": "borshSerializationError", "code": 129, "message": "Borsh Serialization Error", "docs": ["BorshSerializationError: Borsh Serialization Error"] }, { "kind": "errorNode", "name": "noFreezeAuthoritySet", "code": 130, "message": "Cannot create NFT with no Freeze Authority.", "docs": ["NoFreezeAuthoritySet: Cannot create NFT with no Freeze Authority."] }, { "kind": "errorNode", "name": "invalidCollectionSizeChange", "code": 131, "message": "Invalid collection size change", "docs": ["InvalidCollectionSizeChange: Invalid collection size change"] }, { "kind": "errorNode", "name": "invalidBubblegumSigner", "code": 132, "message": "Invalid bubblegum signer", "docs": ["InvalidBubblegumSigner: Invalid bubblegum signer"] }, { "kind": "errorNode", "name": "escrowParentHasDelegate", "code": 133, "message": "Escrow parent cannot have a delegate", "docs": ["EscrowParentHasDelegate: Escrow parent cannot have a delegate"] }, { "kind": "errorNode", "name": "mintIsNotSigner", "code": 134, "message": "Mint needs to be signer to initialize the account", "docs": ["MintIsNotSigner: Mint needs to be signer to initialize the account"] }, { "kind": "errorNode", "name": "invalidTokenStandard", "code": 135, "message": "Invalid token standard", "docs": ["InvalidTokenStandard: Invalid token standard"] }, { "kind": "errorNode", "name": "invalidMintForTokenStandard", "code": 136, "message": "Invalid mint account for specified token standard", "docs": ["InvalidMintForTokenStandard: Invalid mint account for specified token standard"] }, { "kind": "errorNode", "name": "invalidAuthorizationRules", "code": 137, "message": "Invalid authorization rules account", "docs": ["InvalidAuthorizationRules: Invalid authorization rules account"] }, { "kind": "errorNode", "name": "missingAuthorizationRules", "code": 138, "message": "Missing authorization rules account", "docs": ["MissingAuthorizationRules: Missing authorization rules account"] }, { "kind": "errorNode", "name": "missingProgrammableConfig", "code": 139, "message": "Missing programmable configuration", "docs": ["MissingProgrammableConfig: Missing programmable configuration"] }, { "kind": "errorNode", "name": "invalidProgrammableConfig", "code": 140, "message": "Invalid programmable configuration", "docs": ["InvalidProgrammableConfig: Invalid programmable configuration"] }, { "kind": "errorNode", "name": "delegateAlreadyExists", "code": 141, "message": "Delegate already exists", "docs": ["DelegateAlreadyExists: Delegate already exists"] }, { "kind": "errorNode", "name": "delegateNotFound", "code": 142, "message": "Delegate not found", "docs": ["DelegateNotFound: Delegate not found"] }, { "kind": "errorNode", "name": "missingAccountInBuilder", "code": 143, "message": "Required account not set in instruction builder", "docs": ["MissingAccountInBuilder: Required account not set in instruction builder"] }, { "kind": "errorNode", "name": "missingArgumentInBuilder", "code": 144, "message": "Required argument not set in instruction builder", "docs": ["MissingArgumentInBuilder: Required argument not set in instruction builder"] }, { "kind": "errorNode", "name": "featureNotSupported", "code": 145, "message": "Feature not supported currently", "docs": ["FeatureNotSupported: Feature not supported currently"] }, { "kind": "errorNode", "name": "invalidSystemWallet", "code": 146, "message": "Invalid system wallet", "docs": ["InvalidSystemWallet: Invalid system wallet"] }, { "kind": "errorNode", "name": "onlySaleDelegateCanTransfer", "code": 147, "message": "Only the sale delegate can transfer while its set", "docs": ["OnlySaleDelegateCanTransfer: Only the sale delegate can transfer while its set"] }, { "kind": "errorNode", "name": "missingTokenAccount", "code": 148, "message": "Missing token account", "docs": ["MissingTokenAccount: Missing token account"] }, { "kind": "errorNode", "name": "missingSplTokenProgram", "code": 149, "message": "Missing SPL token program", "docs": ["MissingSplTokenProgram: Missing SPL token program"] }, { "kind": "errorNode", "name": "missingAuthorizationRulesProgram", "code": 150, "message": "Missing authorization rules program", "docs": ["MissingAuthorizationRulesProgram: Missing authorization rules program"] }, { "kind": "errorNode", "name": "invalidDelegateRoleForTransfer", "code": 151, "message": "Invalid delegate role for transfer", "docs": ["InvalidDelegateRoleForTransfer: Invalid delegate role for transfer"] }, { "kind": "errorNode", "name": "invalidTransferAuthority", "code": 152, "message": "Invalid transfer authority", "docs": ["InvalidTransferAuthority: Invalid transfer authority"] }, { "kind": "errorNode", "name": "instructionNotSupported", "code": 153, "message": "Instruction not supported for ProgrammableNonFungible assets", "docs": ["InstructionNotSupported: Instruction not supported for ProgrammableNonFungible assets"] }, { "kind": "errorNode", "name": "keyMismatch", "code": 154, "message": "Public key does not match expected value", "docs": ["KeyMismatch: Public key does not match expected value"] }, { "kind": "errorNode", "name": "lockedToken", "code": 155, "message": "Token is locked", "docs": ["LockedToken: Token is locked"] }, { "kind": "errorNode", "name": "unlockedToken", "code": 156, "message": "Token is unlocked", "docs": ["UnlockedToken: Token is unlocked"] }, { "kind": "errorNode", "name": "missingDelegateRole", "code": 157, "message": "Missing delegate role", "docs": ["MissingDelegateRole: Missing delegate role"] }, { "kind": "errorNode", "name": "invalidAuthorityType", "code": 158, "message": "Invalid authority type", "docs": ["InvalidAuthorityType: Invalid authority type"] }, { "kind": "errorNode", "name": "missingTokenRecord", "code": 159, "message": "Missing token record account", "docs": ["MissingTokenRecord: Missing token record account"] }, { "kind": "errorNode", "name": "mintSupplyMustBeZero", "code": 160, "message": "Mint supply must be zero for programmable assets", "docs": ["MintSupplyMustBeZero: Mint supply must be zero for programmable assets"] }, { "kind": "errorNode", "name": "dataIsEmptyOrZeroed", "code": 161, "message": "Data is empty or zeroed", "docs": ["DataIsEmptyOrZeroed: Data is empty or zeroed"] }, { "kind": "errorNode", "name": "missingTokenOwnerAccount", "code": 162, "message": "Missing token owner", "docs": ["MissingTokenOwnerAccount: Missing token owner"] }, { "kind": "errorNode", "name": "invalidMasterEditionAccountLength", "code": 163, "message": "Master edition account has an invalid length", "docs": ["InvalidMasterEditionAccountLength: Master edition account has an invalid length"] }, { "kind": "errorNode", "name": "incorrectTokenState", "code": 164, "message": "Incorrect token state", "docs": ["IncorrectTokenState: Incorrect token state"] }, { "kind": "errorNode", "name": "invalidDelegateRole", "code": 165, "message": "Invalid delegate role", "docs": ["InvalidDelegateRole: Invalid delegate role"] }, { "kind": "errorNode", "name": "missingPrintSupply", "code": 166, "message": "Print supply is required for non-fungibles", "docs": ["MissingPrintSupply: Print supply is required for non-fungibles"] }, { "kind": "errorNode", "name": "missingMasterEditionAccount", "code": 167, "message": "Missing master edition account", "docs": ["MissingMasterEditionAccount: Missing master edition account"] }, { "kind": "errorNode", "name": "amountMustBeGreaterThanZero", "code": 168, "message": "Amount must be greater than zero", "docs": ["AmountMustBeGreaterThanZero: Amount must be greater than zero"] }, { "kind": "errorNode", "name": "invalidDelegateArgs", "code": 169, "message": "Invalid delegate args", "docs": ["InvalidDelegateArgs: Invalid delegate args"] }, { "kind": "errorNode", "name": "missingLockedTransferAddress", "code": 170, "message": "Missing address for locked transfer", "docs": ["MissingLockedTransferAddress: Missing address for locked transfer"] }, { "kind": "errorNode", "name": "invalidLockedTransferAddress", "code": 171, "message": "Invalid destination address for locked transfer", "docs": ["InvalidLockedTransferAddress: Invalid destination address for locked transfer"] }, { "kind": "errorNode", "name": "dataIncrementLimitExceeded", "code": 172, "message": "Exceeded account realloc increase limit", "docs": ["DataIncrementLimitExceeded: Exceeded account realloc increase limit"] }, { "kind": "errorNode", "name": "cannotUpdateAssetWithDelegate", "code": 173, "message": "Cannot update the rule set of a programmable asset that has a delegate", "docs": [ "CannotUpdateAssetWithDelegate: Cannot update the rule set of a programmable asset that has a delegate" ] }, { "kind": "errorNode", "name": "invalidAmount", "code": 174, "message": "Invalid token amount for this operation or token standard", "docs": ["InvalidAmount: Invalid token amount for this operation or token standard"] }, { "kind": "errorNode", "name": "missingMasterEditionMintAccount", "code": 175, "message": "Missing master edition mint account", "docs": ["MissingMasterEditionMintAccount: Missing master edition mint account"] }, { "kind": "errorNode", "name": "missingMasterEditionTokenAccount", "code": 176, "message": "Missing master edition token account", "docs": ["MissingMasterEditionTokenAccount: Missing master edition token account"] }, { "kind": "errorNode", "name": "missingEditionMarkerAccount", "code": 177, "message": "Missing edition marker account", "docs": ["MissingEditionMarkerAccount: Missing edition marker account"] }, { "kind": "errorNode", "name": "cannotBurnWithDelegate", "code": 178, "message": "Cannot burn while persistent delegate is set", "docs": ["CannotBurnWithDelegate: Cannot burn while persistent delegate is set"] }, { "kind": "errorNode", "name": "missingEdition", "code": 179, "message": "Missing edition account", "docs": ["MissingEdition: Missing edition account"] }, { "kind": "errorNode", "name": "invalidAssociatedTokenAccountProgram", "code": 180, "message": "Invalid Associated Token Account Program", "docs": ["InvalidAssociatedTokenAccountProgram: Invalid Associated Token Account Program"] }, { "kind": "errorNode", "name": "invalidInstructionsSysvar", "code": 181, "message": "Invalid InstructionsSysvar", "docs": ["InvalidInstructionsSysvar: Invalid InstructionsSysvar"] }, { "kind": "errorNode", "name": "invalidParentAccounts", "code": 182, "message": "Invalid or Unneeded parent accounts", "docs": ["InvalidParentAccounts: Invalid or Unneeded parent accounts"] }, { "kind": "errorNode", "name": "invalidUpdateArgs", "code": 183, "message": "Authority cannot apply all update args", "docs": ["InvalidUpdateArgs: Authority cannot apply all update args"] }, { "kind": "errorNode", "name": "insufficientTokenBalance", "code": 184, "message": "Token account does not have enough tokens", "docs": ["InsufficientTokenBalance: Token account does not have enough tokens"] }, { "kind": "errorNode", "name": "missingCollectionMint", "code": 185, "message": "Missing collection account", "docs": ["MissingCollectionMint: Missing collection account"] }, { "kind": "errorNode", "name": "missingCollectionMasterEdition", "code": 186, "message": "Missing collection master edition account", "docs": ["MissingCollectionMasterEdition: Missing collection master edition account"] }, { "kind": "errorNode", "name": "invalidTokenRecord", "code": 187, "message": "Invalid token record account", "docs": ["InvalidTokenRecord: Invalid token record account"] }, { "kind": "errorNode", "name": "invalidCloseAuthority", "code": 188, "message": "The close authority needs to be revoked by the Utility Delegate", "docs": ["InvalidCloseAuthority: The close authority needs to be revoked by the Utility Delegate"] }, { "kind": "errorNode", "name": "invalidInstruction", "code": 189, "message": "Invalid or removed instruction", "docs": ["InvalidInstruction: Invalid or removed instruction"] }, { "kind": "errorNode", "name": "missingDelegateRecord", "code": 190, "message": "Missing delegate record", "docs": ["MissingDelegateRecord: Missing delegate record"] }, { "kind": "errorNode", "name": "invalidFeeAccount", "code": 191, "message": "", "docs": ["InvalidFeeAccount"] }, { "kind": "errorNode", "name": "invalidMetadataFlags", "code": 192, "message": "", "docs": ["InvalidMetadataFlags"] }, { "kind": "errorNode", "name": "cannotChangeUpdateAuthorityWithDelegate", "code": 193, "message": "Cannot change the update authority with a delegate", "docs": ["CannotChangeUpdateAuthorityWithDelegate: Cannot change the update authority with a delegate"] }, { "kind": "errorNode", "name": "invalidMintExtensionType", "code": 194, "message": "Invalid mint extension type", "docs": ["InvalidMintExtensionType: Invalid mint extension type"] }, { "kind": "errorNode", "name": "invalidMintCloseAuthority", "code": 195, "message": "Invalid mint close authority", "docs": ["InvalidMintCloseAuthority: Invalid mint close authority"] }, { "kind": "errorNode", "name": "invalidMetadataPointer", "code": 196, "message": "Invalid metadata pointer", "docs": ["InvalidMetadataPointer: Invalid metadata pointer"] }, { "kind": "errorNode", "name": "invalidTokenExtensionType", "code": 197, "message": "Invalid token extension type", "docs": ["InvalidTokenExtensionType: Invalid token extension type"] }, { "kind": "errorNode", "name": "missingImmutableOwnerExtension", "code": 198, "message": "Missing immutable owner extension", "docs": ["MissingImmutableOwnerExtension: Missing immutable owner extension"] }, { "kind": "errorNode", "name": "expectedUninitializedAccount", "code": 199, "message": "Expected account to be uninitialized", "docs": ["ExpectedUninitializedAccount: Expected account to be uninitialized"] }, { "kind": "errorNode", "name": "invalidEditionAccountLength", "code": 200, "message": "Edition account has an invalid length", "docs": ["InvalidEditionAccountLength: Edition account has an invalid length"] }, { "kind": "errorNode", "name": "accountAlreadyResized", "code": 201, "message": "Account has already been resized", "docs": ["AccountAlreadyResized: Account has already been resized"] }, { "kind": "errorNode", "name": "conditionsForClosingNotMet", "code": 202, "message": "Conditions for closing not met", "docs": ["ConditionsForClosingNotMet: Conditions for closing not met"] } ] }, "additionalPrograms": [] } ================================================ FILE: packages/dynamic-client/test/programs/idls/pmp-idl.json ================================================ { "kind": "rootNode", "standard": "codama", "version": "1.0.0", "program": { "kind": "programNode", "name": "programMetadata", "publicKey": "ProgM6JCCvbYkfKqJYHePx4xxSUSqJp7rh8Lyv7nk7S", "version": "0.0.0", "pdas": [ { "kind": "pdaNode", "name": "canonical", "docs": ["The canonical derivation for metadata accounts managed by the program authority itself."], "seeds": [ { "kind": "variablePdaSeedNode", "name": "program", "docs": ["The program to which the metadata belongs."], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "variablePdaSeedNode", "name": "seed", "docs": ["The seed deriving the metadata account."], "type": { "kind": "definedTypeLinkNode", "name": "seed" } } ] }, { "kind": "pdaNode", "name": "nonCanonical", "docs": ["The derivation for metadata accounts managed by third-party authorities."], "seeds": [ { "kind": "variablePdaSeedNode", "name": "program", "docs": ["The program to which the metadata belongs."], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "variablePdaSeedNode", "name": "authority", "docs": ["The third-party authority managing this metadata account."], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "variablePdaSeedNode", "name": "seed", "docs": ["The seed deriving the metadata account."], "type": { "kind": "definedTypeLinkNode", "name": "seed" } } ] }, { "kind": "pdaNode", "name": "metadata", "docs": [ "The derivation for metadata accounts, canonical or not, depending if an authority is provided." ], "seeds": [ { "kind": "variablePdaSeedNode", "name": "program", "docs": ["The program to which the metadata belongs."], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "variablePdaSeedNode", "name": "authority", "docs": ["The third-party authority managing this metadata account, if non-canonical."], "type": { "kind": "remainderOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } }, { "kind": "variablePdaSeedNode", "name": "seed", "docs": ["The seed deriving the metadata account."], "type": { "kind": "definedTypeLinkNode", "name": "seed" } } ] } ], "accounts": [ { "kind": "accountNode", "name": "buffer", "docs": [], "data": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "discriminator", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "accountDiscriminator" }, "defaultValue": { "kind": "enumValueNode", "enum": { "kind": "definedTypeLinkNode", "name": "accountDiscriminator" }, "variant": "buffer" }, "defaultValueStrategy": "omitted" }, { "kind": "structFieldTypeNode", "name": "program", "docs": [], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } }, { "kind": "structFieldTypeNode", "name": "authority", "docs": [], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } }, { "kind": "structFieldTypeNode", "name": "canonical", "docs": [], "type": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "seed", "docs": [], "type": { "kind": "postOffsetTypeNode", "offset": 14, "strategy": "padded", "type": { "kind": "definedTypeLinkNode", "name": "seed" } } }, { "kind": "structFieldTypeNode", "name": "data", "docs": [], "type": { "kind": "bytesTypeNode" } } ] }, "pda": { "kind": "pdaLinkNode", "name": "metadata" } }, { "kind": "accountNode", "name": "metadata", "docs": [], "data": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "discriminator", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "accountDiscriminator" }, "defaultValue": { "kind": "enumValueNode", "enum": { "kind": "definedTypeLinkNode", "name": "accountDiscriminator" }, "variant": "metadata" }, "defaultValueStrategy": "omitted" }, { "kind": "structFieldTypeNode", "name": "program", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "authority", "docs": [], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } }, { "kind": "structFieldTypeNode", "name": "mutable", "docs": [], "type": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "canonical", "docs": [], "type": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "seed", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "seed" } }, { "kind": "structFieldTypeNode", "name": "encoding", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "encoding" } }, { "kind": "structFieldTypeNode", "name": "compression", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "compression" } }, { "kind": "structFieldTypeNode", "name": "format", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "format" } }, { "kind": "structFieldTypeNode", "name": "dataSource", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "dataSource" } }, { "kind": "structFieldTypeNode", "name": "dataLength", "docs": [], "type": { "kind": "postOffsetTypeNode", "offset": 5, "strategy": "padded", "type": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "data", "docs": [], "type": { "kind": "bytesTypeNode" } } ] }, "pda": { "kind": "pdaLinkNode", "name": "metadata" } } ], "instructions": [ { "kind": "instructionNode", "name": "write", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "buffer", "docs": ["The buffer to write to."], "isSigner": false, "isWritable": true }, { "kind": "instructionAccountNode", "name": "authority", "docs": ["The authority of the buffer."], "isSigner": true, "isWritable": false }, { "kind": "instructionAccountNode", "name": "sourceBuffer", "docs": [ "Buffer to copy the data from.", "You may use the `data` argument instead of this account to pass data directly." ], "isSigner": false, "isWritable": false, "isOptional": true } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValueStrategy": "omitted", "defaultValue": { "kind": "numberValueNode", "number": 0 } }, { "kind": "instructionArgumentNode", "name": "offset", "docs": ["The offset to write to."], "type": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } }, { "kind": "instructionArgumentNode", "name": "data", "docs": [ "The data to write at the provided offset.", "You may use the `source_buffer` account instead of this argument to copy from an existing buffer." ], "defaultValue": { "kind": "noneValueNode" }, "type": { "kind": "remainderOptionTypeNode", "item": { "kind": "bytesTypeNode" } } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "initialize", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "metadata", "docs": ["Metadata account the initialize."], "isSigner": false, "isWritable": true, "defaultValue": { "kind": "conditionalValueNode", "condition": { "kind": "accountValueNode", "name": "programData" }, "ifTrue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "canonical" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "program", "value": { "kind": "accountValueNode", "name": "program" } }, { "kind": "pdaSeedValueNode", "name": "seed", "value": { "kind": "argumentValueNode", "name": "seed" } } ] }, "ifFalse": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "nonCanonical" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "program", "value": { "kind": "accountValueNode", "name": "program" } }, { "kind": "pdaSeedValueNode", "name": "authority", "value": { "kind": "accountValueNode", "name": "authority" } }, { "kind": "pdaSeedValueNode", "name": "seed", "value": { "kind": "argumentValueNode", "name": "seed" } } ] } } }, { "kind": "instructionAccountNode", "name": "authority", "docs": ["Authority (for canonical, must match program upgrade authority)."], "isSigner": true, "isWritable": false }, { "kind": "instructionAccountNode", "name": "program", "docs": ["Program account."], "isSigner": false, "isWritable": false }, { "kind": "instructionAccountNode", "name": "programData", "docs": ["Program data account."], "isSigner": false, "isWritable": false, "isOptional": true }, { "kind": "instructionAccountNode", "name": "system", "docs": ["System program."], "isSigner": false, "isWritable": false, "isOptional": true, "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValueStrategy": "omitted", "defaultValue": { "kind": "numberValueNode", "number": 1 } }, { "kind": "instructionArgumentNode", "name": "seed", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "seed" } }, { "kind": "instructionArgumentNode", "name": "encoding", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "encoding" } }, { "kind": "instructionArgumentNode", "name": "compression", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "compression" } }, { "kind": "instructionArgumentNode", "name": "format", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "format" } }, { "kind": "instructionArgumentNode", "name": "dataSource", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "dataSource" } }, { "kind": "instructionArgumentNode", "name": "data", "docs": [], "defaultValue": { "kind": "noneValueNode" }, "type": { "kind": "remainderOptionTypeNode", "item": { "kind": "bytesTypeNode" } } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "setAuthority", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "account", "docs": ["Metadata or buffer account."], "isSigner": false, "isWritable": true }, { "kind": "instructionAccountNode", "name": "authority", "docs": ["Current authority account."], "isSigner": true, "isWritable": false }, { "kind": "instructionAccountNode", "name": "program", "docs": ["Program account."], "isSigner": false, "isWritable": false, "isOptional": true }, { "kind": "instructionAccountNode", "name": "programData", "docs": ["Program data account."], "isSigner": false, "isWritable": false, "isOptional": true } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValueStrategy": "omitted", "defaultValue": { "kind": "numberValueNode", "number": 2 } }, { "kind": "instructionArgumentNode", "name": "newAuthority", "docs": [], "type": { "kind": "optionTypeNode", "item": { "kind": "publicKeyTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "setData", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "metadata", "docs": ["Metadata account."], "isSigner": false, "isWritable": true }, { "kind": "instructionAccountNode", "name": "authority", "docs": ["Authority account."], "isSigner": true, "isWritable": false }, { "kind": "instructionAccountNode", "name": "buffer", "docs": ["Buffer account to copy data from."], "isSigner": false, "isWritable": true, "isOptional": true }, { "kind": "instructionAccountNode", "name": "program", "docs": ["Program account."], "isSigner": false, "isWritable": false, "isOptional": true }, { "kind": "instructionAccountNode", "name": "programData", "docs": ["Program data account."], "isSigner": false, "isWritable": false, "isOptional": true } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValueStrategy": "omitted", "defaultValue": { "kind": "numberValueNode", "number": 3 } }, { "kind": "instructionArgumentNode", "name": "encoding", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "encoding" } }, { "kind": "instructionArgumentNode", "name": "compression", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "compression" } }, { "kind": "instructionArgumentNode", "name": "format", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "format" } }, { "kind": "instructionArgumentNode", "name": "dataSource", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "dataSource" } }, { "kind": "instructionArgumentNode", "name": "data", "defaultValue": { "kind": "noneValueNode" }, "docs": [], "type": { "kind": "remainderOptionTypeNode", "item": { "kind": "bytesTypeNode" } } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "setImmutable", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "metadata", "docs": ["Metadata account."], "isSigner": false, "isWritable": true }, { "kind": "instructionAccountNode", "name": "authority", "docs": ["Authority account."], "isSigner": true, "isWritable": false }, { "kind": "instructionAccountNode", "name": "program", "docs": ["Program account."], "isSigner": false, "isWritable": false, "isOptional": true }, { "kind": "instructionAccountNode", "name": "programData", "docs": ["Program data account."], "isSigner": false, "isWritable": false, "isOptional": true } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValueStrategy": "omitted", "defaultValue": { "kind": "numberValueNode", "number": 4 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "trim", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "account", "docs": ["Buffer or metadata account."], "isSigner": false, "isWritable": true }, { "kind": "instructionAccountNode", "name": "authority", "docs": ["Authority account."], "isSigner": true, "isWritable": false }, { "kind": "instructionAccountNode", "name": "program", "docs": ["Program account."], "isSigner": false, "isWritable": false, "isOptional": true }, { "kind": "instructionAccountNode", "name": "programData", "docs": ["Program data account."], "isSigner": false, "isWritable": false, "isOptional": true }, { "kind": "instructionAccountNode", "name": "destination", "docs": ["Destination account."], "isSigner": false, "isWritable": true }, { "kind": "instructionAccountNode", "name": "rent", "docs": ["Rent sysvar account."], "isSigner": false, "isWritable": false, "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "SysvarRent111111111111111111111111111111111" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValueStrategy": "omitted", "defaultValue": { "kind": "numberValueNode", "number": 5 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "close", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "account", "docs": ["Account to close."], "isSigner": false, "isWritable": true }, { "kind": "instructionAccountNode", "name": "authority", "docs": ["Authority account."], "isSigner": true, "isWritable": false }, { "kind": "instructionAccountNode", "name": "program", "docs": ["Program account."], "isSigner": false, "isWritable": false, "isOptional": true }, { "kind": "instructionAccountNode", "name": "programData", "docs": ["Program data account."], "isSigner": false, "isWritable": false, "isOptional": true }, { "kind": "instructionAccountNode", "name": "destination", "docs": ["Destination account."], "isSigner": false, "isWritable": true } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValueStrategy": "omitted", "defaultValue": { "kind": "numberValueNode", "number": 6 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "allocate", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "buffer", "docs": ["Buffer account to allocate."], "isSigner": false, "isWritable": true }, { "kind": "instructionAccountNode", "name": "authority", "docs": ["Authority account."], "isSigner": true, "isWritable": false }, { "kind": "instructionAccountNode", "name": "program", "docs": ["Program account."], "isSigner": false, "isWritable": false, "isOptional": true }, { "kind": "instructionAccountNode", "name": "programData", "docs": ["Program data account."], "isSigner": false, "isWritable": false, "isOptional": true }, { "kind": "instructionAccountNode", "name": "system", "docs": ["System program."], "isSigner": false, "isWritable": false, "isOptional": true, "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValueStrategy": "omitted", "defaultValue": { "kind": "numberValueNode", "number": 7 } }, { "kind": "instructionArgumentNode", "name": "seed", "docs": ["The seed of the metadata for PDA buffers."], "defaultValue": { "kind": "noneValueNode" }, "type": { "kind": "remainderOptionTypeNode", "item": { "kind": "definedTypeLinkNode", "name": "seed" } } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "extend", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "account", "docs": ["Buffer or metadata account."], "isSigner": false, "isWritable": true }, { "kind": "instructionAccountNode", "name": "authority", "docs": ["Authority account."], "isSigner": true, "isWritable": false }, { "kind": "instructionAccountNode", "name": "program", "docs": ["Program account."], "isSigner": false, "isWritable": false, "isOptional": true }, { "kind": "instructionAccountNode", "name": "programData", "docs": ["Program data account."], "isSigner": false, "isWritable": false, "isOptional": true } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValueStrategy": "omitted", "defaultValue": { "kind": "numberValueNode", "number": 8 } }, { "kind": "instructionArgumentNode", "name": "length", "docs": ["Length (in bytes) to add to the account size."], "type": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] } ], "definedTypes": [ { "kind": "definedTypeNode", "name": "seed", "docs": [], "type": { "kind": "fixedSizeTypeNode", "size": 16, "type": { "kind": "stringTypeNode", "encoding": "utf8" } } }, { "kind": "definedTypeNode", "name": "accountDiscriminator", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumEmptyVariantTypeNode", "name": "empty" }, { "kind": "enumEmptyVariantTypeNode", "name": "buffer" }, { "kind": "enumEmptyVariantTypeNode", "name": "metadata" } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "encoding", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumEmptyVariantTypeNode", "name": "none" }, { "kind": "enumEmptyVariantTypeNode", "name": "utf8" }, { "kind": "enumEmptyVariantTypeNode", "name": "base58" }, { "kind": "enumEmptyVariantTypeNode", "name": "base64" } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "compression", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumEmptyVariantTypeNode", "name": "none" }, { "kind": "enumEmptyVariantTypeNode", "name": "gzip" }, { "kind": "enumEmptyVariantTypeNode", "name": "zlib" } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "format", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumEmptyVariantTypeNode", "name": "none" }, { "kind": "enumEmptyVariantTypeNode", "name": "json" }, { "kind": "enumEmptyVariantTypeNode", "name": "yaml" }, { "kind": "enumEmptyVariantTypeNode", "name": "toml" } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "dataSource", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumEmptyVariantTypeNode", "name": "direct" }, { "kind": "enumEmptyVariantTypeNode", "name": "url" }, { "kind": "enumEmptyVariantTypeNode", "name": "external" } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "externalData", "docs": [], "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "address", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "offset", "docs": [], "type": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "length", "docs": [], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } } ] } } ], "errors": [] }, "additionalPrograms": [] } ================================================ FILE: packages/dynamic-client/test/programs/idls/sas-idl.json ================================================ { "kind": "rootNode", "standard": "codama", "version": "1.3.7", "program": { "kind": "programNode", "name": "solanaAttestationService", "publicKey": "22zoJMtdu4tQc2PzL74ZUT7FrwgB1Udec8DdW4yw4BdG", "version": "0.1.0", "origin": "shank", "docs": [], "accounts": [ { "kind": "accountNode", "name": "attestation", "docs": [], "data": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "nonce", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "credential", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "schema", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "data", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "bytesTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "signer", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "expiry", "docs": [], "type": { "kind": "numberTypeNode", "format": "i64", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "tokenAccount", "docs": [], "type": { "kind": "publicKeyTypeNode" } } ] } }, { "kind": "accountNode", "name": "credential", "docs": [], "data": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "authority", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "name", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "bytesTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "authorizedSigners", "docs": [], "type": { "kind": "arrayTypeNode", "item": { "kind": "publicKeyTypeNode" }, "count": { "kind": "prefixedCountNode", "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } } } ] } }, { "kind": "accountNode", "name": "schema", "docs": [], "data": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "credential", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "name", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "bytesTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "description", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "bytesTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "layout", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "bytesTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "fieldNames", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "bytesTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "isPaused", "docs": [], "type": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "version", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } ] } } ], "instructions": [ { "kind": "instructionNode", "name": "createCredential", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "credential", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": [], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 0 } }, { "kind": "instructionArgumentNode", "name": "name", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "instructionArgumentNode", "name": "signers", "docs": [], "type": { "kind": "arrayTypeNode", "item": { "kind": "publicKeyTypeNode" }, "count": { "kind": "prefixedCountNode", "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "createSchema", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": [], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "credential", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Credential the Schema is associated with"] }, { "kind": "instructionAccountNode", "name": "schema", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } }, { "kind": "instructionArgumentNode", "name": "name", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "instructionArgumentNode", "name": "description", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "instructionArgumentNode", "name": "layout", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "bytesTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "instructionArgumentNode", "name": "fieldNames", "docs": [], "type": { "kind": "arrayTypeNode", "item": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } }, "count": { "kind": "prefixedCountNode", "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "changeSchemaStatus", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": [], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "credential", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Credential the Schema is associated with"] }, { "kind": "instructionAccountNode", "name": "schema", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Credential the Schema is associated with"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 2 } }, { "kind": "instructionArgumentNode", "name": "isPaused", "docs": [], "type": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "changeAuthorizedSigners", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": [], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "credential", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Credential the Schema is associated with"] }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 3 } }, { "kind": "instructionArgumentNode", "name": "signers", "docs": [], "type": { "kind": "arrayTypeNode", "item": { "kind": "publicKeyTypeNode" }, "count": { "kind": "prefixedCountNode", "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "changeSchemaDescription", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": [], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "credential", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Credential the Schema is associated with"] }, { "kind": "instructionAccountNode", "name": "schema", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Credential the Schema is associated with"] }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 4 } }, { "kind": "instructionArgumentNode", "name": "description", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "changeSchemaVersion", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": [], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "credential", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Credential the Schema is associated with"] }, { "kind": "instructionAccountNode", "name": "existingSchema", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "newSchema", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 5 } }, { "kind": "instructionArgumentNode", "name": "layout", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "bytesTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "instructionArgumentNode", "name": "fieldNames", "docs": [], "type": { "kind": "arrayTypeNode", "item": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } }, "count": { "kind": "prefixedCountNode", "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "createAttestation", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Authorized signer of the Schema's Credential"], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "credential", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Credential the Schema is associated with"] }, { "kind": "instructionAccountNode", "name": "schema", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Schema the Attestation is associated with"] }, { "kind": "instructionAccountNode", "name": "attestation", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 6 } }, { "kind": "instructionArgumentNode", "name": "nonce", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "instructionArgumentNode", "name": "data", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "bytesTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "instructionArgumentNode", "name": "expiry", "docs": [], "type": { "kind": "numberTypeNode", "format": "i64", "endian": "le" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "closeAttestation", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Authorized signer of the Schema's Credential"], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "credential", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "attestation", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "eventAuthority", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "attestationProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 7 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "tokenizeSchema", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": [], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "credential", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Credential the Schema is associated with"] }, { "kind": "instructionAccountNode", "name": "schema", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Mint of Schema Token"] }, { "kind": "instructionAccountNode", "name": "sasPda", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Program derived address used as program signer authority"] }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "tokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 9 } }, { "kind": "instructionArgumentNode", "name": "maxSize", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "createTokenizedAttestation", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Authorized signer of the Schema's Credential"], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "credential", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Credential the Schema is associated with"] }, { "kind": "instructionAccountNode", "name": "schema", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Schema the Attestation is associated with"] }, { "kind": "instructionAccountNode", "name": "attestation", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "schemaMint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Mint of Schema Token"] }, { "kind": "instructionAccountNode", "name": "attestationMint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Mint of Attestation Token"] }, { "kind": "instructionAccountNode", "name": "sasPda", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Program derived address used as program signer authority"] }, { "kind": "instructionAccountNode", "name": "recipientTokenAccount", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Associated token account of Recipient for Attestation Token"] }, { "kind": "instructionAccountNode", "name": "recipient", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Wallet to receive Attestation Token"] }, { "kind": "instructionAccountNode", "name": "tokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } }, { "kind": "instructionAccountNode", "name": "associatedTokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 10 } }, { "kind": "instructionArgumentNode", "name": "nonce", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "instructionArgumentNode", "name": "data", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "bytesTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "instructionArgumentNode", "name": "expiry", "docs": [], "type": { "kind": "numberTypeNode", "format": "i64", "endian": "le" } }, { "kind": "instructionArgumentNode", "name": "name", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "instructionArgumentNode", "name": "uri", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "instructionArgumentNode", "name": "symbol", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "instructionArgumentNode", "name": "mintAccountSpace", "docs": [], "type": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "closeTokenizedAttestation", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Authorized signer of the Schema's Credential"], "defaultValue": { "kind": "identityValueNode" } }, { "kind": "instructionAccountNode", "name": "credential", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "attestation", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "eventAuthority", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111", "identifier": "splSystem" } }, { "kind": "instructionAccountNode", "name": "attestationProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "attestationMint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Mint of Attestation Token"] }, { "kind": "instructionAccountNode", "name": "sasPda", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Program derived address used as program signer authority"] }, { "kind": "instructionAccountNode", "name": "attestationTokenAccount", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Associated token account of the related Attestation Token"] }, { "kind": "instructionAccountNode", "name": "tokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "identifier": "splToken" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 11 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "emitEvent", "docs": [], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "eventAuthority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": [] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 228 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] } ], "definedTypes": [ { "kind": "definedTypeNode", "name": "closeAttestationEvent", "docs": [], "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "discriminator", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "schema", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "attestationData", "docs": [], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "bytesTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } } ] } } ], "pdas": [], "errors": [] }, "additionalPrograms": [] } ================================================ FILE: packages/dynamic-client/test/programs/idls/system-program-idl.json ================================================ { "kind": "rootNode", "program": { "kind": "programNode", "pdas": [], "accounts": [ { "kind": "accountNode", "data": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "version", "type": { "kind": "definedTypeLinkNode", "name": "nonceVersion" }, "docs": [] }, { "kind": "structFieldTypeNode", "name": "state", "type": { "kind": "definedTypeLinkNode", "name": "nonceState" }, "docs": [] }, { "kind": "structFieldTypeNode", "name": "authority", "type": { "kind": "publicKeyTypeNode" }, "docs": [] }, { "kind": "structFieldTypeNode", "name": "blockhash", "type": { "kind": "publicKeyTypeNode" }, "docs": [] }, { "kind": "structFieldTypeNode", "name": "lamportsPerSignature", "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "docs": [] } ] }, "name": "nonce", "idlName": "Nonce", "docs": [], "size": 80 } ], "instructions": [ { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "newAccount", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u32", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 0 }, "defaultValueStrategy": "omitted" }, { "kind": "instructionArgumentNode", "name": "lamports", "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "docs": [] }, { "kind": "instructionArgumentNode", "name": "space", "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "docs": [] }, { "kind": "instructionArgumentNode", "name": "programAddress", "type": { "kind": "publicKeyTypeNode" }, "docs": [] } ], "byteDeltas": [ { "kind": "instructionByteDeltaNode", "value": { "kind": "argumentValueNode", "name": "space" }, "withHeader": true } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "name": "createAccount", "idlName": "CreateAccount", "docs": [], "optionalAccountStrategy": "omitted" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "account", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u32", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 1 }, "defaultValueStrategy": "omitted" }, { "kind": "instructionArgumentNode", "name": "programAddress", "type": { "kind": "publicKeyTypeNode" }, "docs": [] } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "name": "assign", "idlName": "Assign", "docs": [], "optionalAccountStrategy": "omitted" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "source", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "destination", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u32", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 2 }, "defaultValueStrategy": "omitted" }, { "kind": "instructionArgumentNode", "name": "amount", "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "docs": [] } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "name": "transferSol", "idlName": "TransferSol", "docs": [], "optionalAccountStrategy": "omitted" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "newAccount", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "baseAccount", "isWritable": false, "isSigner": true, "isOptional": true, "docs": [] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u32", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 3 }, "defaultValueStrategy": "omitted" }, { "kind": "instructionArgumentNode", "name": "base", "type": { "kind": "publicKeyTypeNode" }, "docs": [] }, { "kind": "instructionArgumentNode", "name": "seed", "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, "docs": [] }, { "kind": "instructionArgumentNode", "name": "amount", "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "docs": [] }, { "kind": "instructionArgumentNode", "name": "space", "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "docs": [] }, { "kind": "instructionArgumentNode", "name": "programAddress", "type": { "kind": "publicKeyTypeNode" }, "docs": [] } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "name": "createAccountWithSeed", "idlName": "CreateAccountWithSeed", "docs": [], "optionalAccountStrategy": "omitted" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "nonceAccount", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "recentBlockhashesSysvar", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "SysvarRecentB1ockHashes11111111111111111111" } }, { "kind": "instructionAccountNode", "name": "nonceAuthority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": [] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u32", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 4 }, "defaultValueStrategy": "omitted" } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "name": "advanceNonceAccount", "idlName": "AdvanceNonceAccount", "docs": [], "optionalAccountStrategy": "omitted" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "nonceAccount", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "recipientAccount", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "recentBlockhashesSysvar", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "SysvarRecentB1ockHashes11111111111111111111" } }, { "kind": "instructionAccountNode", "name": "rentSysvar", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "SysvarRent111111111111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "nonceAuthority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": [] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u32", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 5 }, "defaultValueStrategy": "omitted" }, { "kind": "instructionArgumentNode", "name": "withdrawAmount", "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "docs": [] } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "name": "withdrawNonceAccount", "idlName": "WithdrawNonceAccount", "docs": [], "optionalAccountStrategy": "omitted" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "nonceAccount", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "recentBlockhashesSysvar", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "SysvarRecentB1ockHashes11111111111111111111" } }, { "kind": "instructionAccountNode", "name": "rentSysvar", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "SysvarRent111111111111111111111111111111111" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u32", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 6 }, "defaultValueStrategy": "omitted" }, { "kind": "instructionArgumentNode", "name": "nonceAuthority", "type": { "kind": "publicKeyTypeNode" }, "docs": [] } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "name": "initializeNonceAccount", "idlName": "InitializeNonceAccount", "docs": [], "optionalAccountStrategy": "omitted" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "nonceAccount", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "nonceAuthority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": [] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u32", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 7 }, "defaultValueStrategy": "omitted" }, { "kind": "instructionArgumentNode", "name": "newNonceAuthority", "type": { "kind": "publicKeyTypeNode" }, "docs": [] } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "name": "authorizeNonceAccount", "idlName": "AuthorizeNonceAccount", "docs": [], "optionalAccountStrategy": "omitted" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "newAccount", "isWritable": true, "isSigner": true, "isOptional": false, "docs": [] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u32", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 8 }, "defaultValueStrategy": "omitted" }, { "kind": "instructionArgumentNode", "name": "space", "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "docs": [] } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "name": "allocate", "idlName": "Allocate", "docs": [], "optionalAccountStrategy": "omitted" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "newAccount", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "baseAccount", "isWritable": false, "isSigner": true, "isOptional": false, "docs": [] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u32", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 9 }, "defaultValueStrategy": "omitted" }, { "kind": "instructionArgumentNode", "name": "base", "type": { "kind": "publicKeyTypeNode" }, "docs": [] }, { "kind": "instructionArgumentNode", "name": "seed", "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, "docs": [] }, { "kind": "instructionArgumentNode", "name": "space", "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "docs": [] }, { "kind": "instructionArgumentNode", "name": "programAddress", "type": { "kind": "publicKeyTypeNode" }, "docs": [] } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "name": "allocateWithSeed", "idlName": "AllocateWithSeed", "docs": [], "optionalAccountStrategy": "omitted" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "account", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "baseAccount", "isWritable": false, "isSigner": true, "isOptional": false, "docs": [] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u32", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 10 }, "defaultValueStrategy": "omitted" }, { "kind": "instructionArgumentNode", "name": "base", "type": { "kind": "publicKeyTypeNode" }, "docs": [] }, { "kind": "instructionArgumentNode", "name": "seed", "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, "docs": [] }, { "kind": "instructionArgumentNode", "name": "programAddress", "type": { "kind": "publicKeyTypeNode" }, "docs": [] } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "name": "assignWithSeed", "idlName": "AssignWithSeed", "docs": [], "optionalAccountStrategy": "omitted" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "source", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "baseAccount", "isWritable": false, "isSigner": true, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "destination", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u32", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 11 }, "defaultValueStrategy": "omitted" }, { "kind": "instructionArgumentNode", "name": "amount", "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "docs": [] }, { "kind": "instructionArgumentNode", "name": "fromSeed", "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, "docs": [] }, { "kind": "instructionArgumentNode", "name": "fromOwner", "type": { "kind": "publicKeyTypeNode" }, "docs": [] } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "name": "transferSolWithSeed", "idlName": "TransferSolWithSeed", "docs": [], "optionalAccountStrategy": "omitted" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "nonceAccount", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u32", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 12 }, "defaultValueStrategy": "omitted" } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "name": "upgradeNonceAccount", "idlName": "UpgradeNonceAccount", "docs": [], "optionalAccountStrategy": "omitted" } ], "definedTypes": [ { "kind": "definedTypeNode", "name": "nonceVersion", "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumEmptyVariantTypeNode", "name": "legacy" }, { "kind": "enumEmptyVariantTypeNode", "name": "current" } ], "size": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } }, "idlName": "NonceVersion", "docs": [] }, { "kind": "definedTypeNode", "name": "nonceState", "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumEmptyVariantTypeNode", "name": "uninitialized" }, { "kind": "enumEmptyVariantTypeNode", "name": "initialized" } ], "size": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } }, "idlName": "NonceState", "docs": [] } ], "errors": [ { "kind": "errorNode", "name": "accountAlreadyInUse", "idlName": "AccountAlreadyInUse", "code": 0, "message": "an account with the same address already exists", "docs": ["AccountAlreadyInUse: an account with the same address already exists"] }, { "kind": "errorNode", "name": "resultWithNegativeLamports", "idlName": "ResultWithNegativeLamports", "code": 1, "message": "account does not have enough SOL to perform the operation", "docs": ["ResultWithNegativeLamports: account does not have enough SOL to perform the operation"] }, { "kind": "errorNode", "name": "invalidProgramId", "idlName": "InvalidProgramId", "code": 2, "message": "cannot assign account to this program id", "docs": ["InvalidProgramId: cannot assign account to this program id"] }, { "kind": "errorNode", "name": "invalidAccountDataLength", "idlName": "InvalidAccountDataLength", "code": 3, "message": "cannot allocate account data of this length", "docs": ["InvalidAccountDataLength: cannot allocate account data of this length"] }, { "kind": "errorNode", "name": "maxSeedLengthExceeded", "idlName": "MaxSeedLengthExceeded", "code": 4, "message": "length of requested seed is too long", "docs": ["MaxSeedLengthExceeded: length of requested seed is too long"] }, { "kind": "errorNode", "name": "addressWithSeedMismatch", "idlName": "AddressWithSeedMismatch", "code": 5, "message": "provided address does not match addressed derived from seed", "docs": ["AddressWithSeedMismatch: provided address does not match addressed derived from seed"] }, { "kind": "errorNode", "name": "nonceNoRecentBlockhashes", "idlName": "NonceNoRecentBlockhashes", "code": 6, "message": "advancing stored nonce requires a populated RecentBlockhashes sysvar", "docs": [ "NonceNoRecentBlockhashes: advancing stored nonce requires a populated RecentBlockhashes sysvar" ] }, { "kind": "errorNode", "name": "nonceBlockhashNotExpired", "idlName": "NonceBlockhashNotExpired", "code": 7, "message": "stored nonce is still in recent_blockhashes", "docs": ["NonceBlockhashNotExpired: stored nonce is still in recent_blockhashes"] }, { "kind": "errorNode", "name": "nonceUnexpectedBlockhashValue", "idlName": "NonceUnexpectedBlockhashValue", "code": 8, "message": "specified nonce does not match stored nonce", "docs": ["NonceUnexpectedBlockhashValue: specified nonce does not match stored nonce"] } ], "name": "system", "prefix": "", "publicKey": "11111111111111111111111111111111", "version": "0.0.1", "origin": "shank" }, "additionalPrograms": [], "standard": "codama", "version": "1.0.0" } ================================================ FILE: packages/dynamic-client/test/programs/idls/token-2022-idl.json ================================================ { "kind": "rootNode", "standard": "codama", "version": "1.0.0", "program": { "kind": "programNode", "name": "token-2022", "publicKey": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb", "version": "3.0.2", "origin": "shank", "docs": [], "accounts": [ { "kind": "accountNode", "name": "mint", "docs": [], "data": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "mintAuthority", "docs": [ "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." ], "type": { "kind": "optionTypeNode", "fixed": true, "item": { "kind": "publicKeyTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "supply", "docs": ["Total supply of tokens."], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "decimals", "docs": ["Number of base 10 digits to the right of the decimal place."], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "isInitialized", "docs": ["Is `true` if this structure has been initialized."], "type": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "freezeAuthority", "docs": ["Optional authority to freeze token accounts."], "type": { "kind": "optionTypeNode", "fixed": true, "item": { "kind": "publicKeyTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "extensions", "docs": ["The extensions activated on the mint account."], "type": { "kind": "remainderOptionTypeNode", "item": { "kind": "hiddenPrefixTypeNode", "type": { "kind": "arrayTypeNode", "item": { "kind": "definedTypeLinkNode", "name": "extension" }, "count": { "kind": "remainderCountNode" } }, "prefix": [ { "kind": "constantValueNode", "type": { "kind": "preOffsetTypeNode", "offset": 83, "strategy": "padded", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "value": { "kind": "numberValueNode", "number": 1 } } ] } } } ] }, "discriminators": [ { "kind": "sizeDiscriminatorNode", "size": 82 } ] }, { "kind": "accountNode", "name": "token", "docs": [], "data": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "mint", "docs": ["The mint associated with this account."], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "owner", "docs": ["The owner of this account."], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "amount", "docs": ["The amount of tokens this account holds."], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "delegate", "docs": [ "If `delegate` is `Some` then `delegated_amount` represents", "the amount authorized by the delegate." ], "type": { "kind": "optionTypeNode", "fixed": true, "item": { "kind": "publicKeyTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "state", "docs": ["The account's state."], "type": { "kind": "definedTypeLinkNode", "name": "accountState" } }, { "kind": "structFieldTypeNode", "name": "isNative", "docs": [ "If is_native.is_some, this is a native token, and the value logs the", "rent-exempt reserve. An Account is required to be rent-exempt, so", "the value is used by the Processor to ensure that wrapped SOL", "accounts do not drop below this threshold." ], "type": { "kind": "optionTypeNode", "fixed": true, "item": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "delegatedAmount", "docs": ["The amount delegated."], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "closeAuthority", "docs": ["Optional authority to close the account."], "type": { "kind": "optionTypeNode", "fixed": true, "item": { "kind": "publicKeyTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "extensions", "docs": ["The extensions activated on the token account."], "type": { "kind": "remainderOptionTypeNode", "item": { "kind": "hiddenPrefixTypeNode", "type": { "kind": "arrayTypeNode", "item": { "kind": "definedTypeLinkNode", "name": "extension" }, "count": { "kind": "remainderCountNode" } }, "prefix": [ { "kind": "constantValueNode", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "value": { "kind": "numberValueNode", "number": 2 } } ] } } } ] }, "discriminators": [ { "kind": "sizeDiscriminatorNode", "size": 165 } ] }, { "kind": "accountNode", "name": "multisig", "size": 355, "docs": [], "data": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "m", "docs": ["Number of signers required."], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "n", "docs": ["Number of valid signers."], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "isInitialized", "docs": ["Is `true` if this structure has been initialized."], "type": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "signers", "docs": ["Signer public keys."], "type": { "kind": "arrayTypeNode", "item": { "kind": "publicKeyTypeNode" }, "count": { "kind": "fixedCountNode", "value": 11 } } } ] }, "discriminators": [ { "kind": "sizeDiscriminatorNode", "size": 355 } ] } ], "instructions": [ { "kind": "instructionNode", "name": "initializeMint", "docs": [ "Initializes a new mint and optionally deposits all the newly minted", "tokens in an account.", "", "The `InitializeMint` instruction requires no signers and MUST be", "included within the same Transaction as the system program's", "`CreateAccount` instruction that creates the account being initialized.", "Otherwise another party can acquire ownership of the uninitialized account." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token mint account."] }, { "kind": "instructionAccountNode", "name": "rent", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Rent sysvar."], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "SysvarRent111111111111111111111111111111111" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 0 } }, { "kind": "instructionArgumentNode", "name": "decimals", "docs": ["Number of decimals in token account amounts."], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, { "kind": "instructionArgumentNode", "name": "mintAuthority", "docs": ["Minting authority."], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "instructionArgumentNode", "name": "freezeAuthority", "docs": ["Optional authority that can freeze token accounts."], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "publicKeyTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "initializeAccount", "docs": [ "Initializes a new account to hold tokens. If this account is associated", "with the native mint then the token balance of the initialized account", "will be equal to the amount of SOL in the account. If this account is", "associated with another mint, that mint must be initialized before this", "command can succeed.", "", "The `InitializeAccount` instruction requires no signers and MUST be", "included within the same Transaction as the system program's", "`CreateAccount` instruction that creates the account being initialized.", "Otherwise another party can acquire ownership of the uninitialized account." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "account", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The account to initialize."] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The mint this account will be associated with."] }, { "kind": "instructionAccountNode", "name": "owner", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The new account's owner/multisignature."] }, { "kind": "instructionAccountNode", "name": "rent", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Rent sysvar."], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "SysvarRent111111111111111111111111111111111" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "initializeMultisig", "docs": [ "Initializes a multisignature account with N provided signers.", "", "Multisignature accounts can used in place of any single owner/delegate", "accounts in any token instruction that require an owner/delegate to be", "present. The variant field represents the number of signers (M)", "required to validate this multisignature account.", "", "The `InitializeMultisig` instruction requires no signers and MUST be", "included within the same Transaction as the system program's", "`CreateAccount` instruction that creates the account being initialized.", "Otherwise another party can acquire ownership of the uninitialized account." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "multisig", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The multisignature account to initialize."] }, { "kind": "instructionAccountNode", "name": "rent", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Rent sysvar."], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "SysvarRent111111111111111111111111111111111" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 2 } }, { "kind": "instructionArgumentNode", "name": "m", "docs": ["The number of signers (M) required to validate this multisignature account."], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "docs": [], "value": { "kind": "argumentValueNode", "name": "signers" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "transfer", "docs": [ "Transfers tokens from one account to another either directly or via a delegate.", "If this account is associated with the native mint then equal amounts", "of SOL and Tokens will be transferred to the destination account." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "source", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The source account."] }, { "kind": "instructionAccountNode", "name": "destination", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The destination account."] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The source account's owner/delegate or its multisignature account."], "defaultValue": { "kind": "identityValueNode" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 3 } }, { "kind": "instructionArgumentNode", "name": "amount", "docs": ["The amount of tokens to transfer."], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "approve", "docs": [ "Approves a delegate. A delegate is given the authority over tokens on", "behalf of the source account's owner." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "source", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The source account."] }, { "kind": "instructionAccountNode", "name": "delegate", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The delegate."] }, { "kind": "instructionAccountNode", "name": "owner", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The source account owner or its multisignature account."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 4 } }, { "kind": "instructionArgumentNode", "name": "amount", "docs": ["The amount of tokens the delegate is approved for."], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "revoke", "docs": ["Revokes the delegate's authority."], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "source", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The source account."] }, { "kind": "instructionAccountNode", "name": "owner", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The source account owner or its multisignature."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 5 } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "setAuthority", "docs": ["Sets a new authority of a mint or account."], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "owned", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The mint or account to change the authority of."] }, { "kind": "instructionAccountNode", "name": "owner", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": [ "The current authority or the multisignature account of the mint or account to update." ] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 6 } }, { "kind": "instructionArgumentNode", "name": "authorityType", "docs": ["The type of authority to update."], "type": { "kind": "definedTypeLinkNode", "name": "authorityType" } }, { "kind": "instructionArgumentNode", "name": "newAuthority", "docs": ["The new authority"], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "publicKeyTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "mintTo", "docs": ["Mints new tokens to an account. The native mint does not support minting."], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The mint account."] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The account to mint tokens to."] }, { "kind": "instructionAccountNode", "name": "mintAuthority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The mint's minting authority or its multisignature account."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 7 } }, { "kind": "instructionArgumentNode", "name": "amount", "docs": ["The amount of new tokens to mint."], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "burn", "docs": [ "Burns tokens by removing them from an account. `Burn` does not support", "accounts associated with the native mint, use `CloseAccount` instead." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "account", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The account to burn from."] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The token mint."] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The account's owner/delegate or its multisignature account."], "defaultValue": { "kind": "identityValueNode" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": ["The amount of tokens to burn."], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 8 } }, { "kind": "instructionArgumentNode", "name": "amount", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "closeAccount", "docs": [ "Close an account by transferring all its SOL to the destination account.", "Non-native accounts may only be closed if its token amount is zero." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "account", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The account to close."] }, { "kind": "instructionAccountNode", "name": "destination", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The destination account."] }, { "kind": "instructionAccountNode", "name": "owner", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The account's owner or its multisignature account."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 9 } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "freezeAccount", "docs": ["Freeze an Initialized account using the Mint's freeze_authority (if set)."], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "account", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The account to freeze."] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The token mint."] }, { "kind": "instructionAccountNode", "name": "owner", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The mint freeze authority or its multisignature account."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 10 } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "thawAccount", "docs": ["Thaw a Frozen account using the Mint's freeze_authority (if set)."], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "account", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The account to thaw."] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The token mint."] }, { "kind": "instructionAccountNode", "name": "owner", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The mint freeze authority or its multisignature account."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 11 } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "transferChecked", "docs": [ "Transfers tokens from one account to another either directly or via a", "delegate. If this account is associated with the native mint then equal", "amounts of SOL and Tokens will be transferred to the destination account.", "", "This instruction differs from Transfer in that the token mint and", "decimals value is checked by the caller. This may be useful when", "creating transactions offline or within a hardware wallet." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "source", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The source account."] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The token mint."] }, { "kind": "instructionAccountNode", "name": "destination", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The destination account."] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The source account's owner/delegate or its multisignature account."], "defaultValue": { "kind": "identityValueNode" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 12 } }, { "kind": "instructionArgumentNode", "name": "amount", "docs": ["The amount of tokens to transfer."], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, { "kind": "instructionArgumentNode", "name": "decimals", "docs": ["Expected number of base 10 digits to the right of the decimal place."], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "approveChecked", "docs": [ "Approves a delegate. A delegate is given the authority over tokens on", "behalf of the source account's owner.", "", "This instruction differs from Approve in that the token mint and", "decimals value is checked by the caller. This may be useful when", "creating transactions offline or within a hardware wallet." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "source", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The source account."] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The token mint."] }, { "kind": "instructionAccountNode", "name": "delegate", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The delegate."] }, { "kind": "instructionAccountNode", "name": "owner", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The source account owner or its multisignature account."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 13 } }, { "kind": "instructionArgumentNode", "name": "amount", "docs": ["The amount of tokens the delegate is approved for."], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, { "kind": "instructionArgumentNode", "name": "decimals", "docs": ["Expected number of base 10 digits to the right of the decimal place."], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "mintToChecked", "docs": [ "Mints new tokens to an account. The native mint does not support minting.", "", "This instruction differs from MintTo in that the decimals value is", "checked by the caller. This may be useful when creating transactions", "offline or within a hardware wallet." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The mint."] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The account to mint tokens to."] }, { "kind": "instructionAccountNode", "name": "mintAuthority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The mint's minting authority or its multisignature account."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 14 } }, { "kind": "instructionArgumentNode", "name": "amount", "docs": ["The amount of new tokens to mint."], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, { "kind": "instructionArgumentNode", "name": "decimals", "docs": ["Expected number of base 10 digits to the right of the decimal place."], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "burnChecked", "docs": [ "Burns tokens by removing them from an account. `BurnChecked` does not", "support accounts associated with the native mint, use `CloseAccount` instead.", "", "This instruction differs from Burn in that the decimals value is checked", "by the caller. This may be useful when creating transactions offline or", "within a hardware wallet." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "account", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The account to burn from."] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The token mint."] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The account's owner/delegate or its multisignature account."], "defaultValue": { "kind": "identityValueNode" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 15 } }, { "kind": "instructionArgumentNode", "name": "amount", "docs": ["The amount of tokens to burn."], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, { "kind": "instructionArgumentNode", "name": "decimals", "docs": ["Expected number of base 10 digits to the right of the decimal place."], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "initializeAccount2", "docs": [ "Like InitializeAccount, but the owner pubkey is passed via instruction", "data rather than the accounts list. This variant may be preferable", "when using Cross Program Invocation from an instruction that does", "not need the owner's `AccountInfo` otherwise." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "account", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The account to initialize."] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The mint this account will be associated with."] }, { "kind": "instructionAccountNode", "name": "rent", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Rent sysvar."], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "SysvarRent111111111111111111111111111111111" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 16 } }, { "kind": "instructionArgumentNode", "name": "owner", "docs": ["The new account's owner/multisignature."], "type": { "kind": "publicKeyTypeNode" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "syncNative", "docs": [ "Given a wrapped / native token account (a token account containing SOL)", "updates its amount field based on the account's underlying `lamports`.", "This is useful if a non-wrapped SOL account uses", "`system_instruction::transfer` to move lamports to a wrapped token", "account, and needs to have its token `amount` field updated." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "account", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The native token account to sync with its underlying lamports."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 17 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "initializeAccount3", "docs": ["Like InitializeAccount2, but does not require the Rent sysvar to be provided."], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "account", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The account to initialize."] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The mint this account will be associated with."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 18 } }, { "kind": "instructionArgumentNode", "name": "owner", "docs": ["The new account's owner/multisignature."], "type": { "kind": "publicKeyTypeNode" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "initializeMultisig2", "docs": ["Like InitializeMultisig, but does not require the Rent sysvar to be provided."], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "multisig", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The multisignature account to initialize."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 19 } }, { "kind": "instructionArgumentNode", "name": "m", "docs": ["The number of signers (M) required to validate this multisignature account."], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "docs": [], "value": { "kind": "argumentValueNode", "name": "signers" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "initializeMint2", "docs": ["Like [`InitializeMint`], but does not require the Rent sysvar to be provided."], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The mint to initialize."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 20 } }, { "kind": "instructionArgumentNode", "name": "decimals", "docs": ["Number of base 10 digits to the right of the decimal place."], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, { "kind": "instructionArgumentNode", "name": "mintAuthority", "docs": ["The authority/multisignature to mint tokens."], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "instructionArgumentNode", "name": "freezeAuthority", "docs": ["The optional freeze authority/multisignature of the mint."], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "publicKeyTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "getAccountDataSize", "docs": [ "Gets the required size of an account for the given mint as a", "little-endian `u64`.", "", "Return data can be fetched using `sol_get_return_data` and deserializing", "the return data as a little-endian `u64`." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The mint to calculate for."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 21 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "initializeImmutableOwner", "docs": [ "Initialize the Immutable Owner extension for the given token account", "", "Fails if the account has already been initialized, so must be called", "before `InitializeAccount`.", "", "No-ops in this version of the program, but is included for compatibility", "with the Associated Token Account program." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "account", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The account to initialize."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 22 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "amountToUiAmount", "docs": [ "Convert an Amount of tokens to a UiAmount `string`, using the given", "mint. In this version of the program, the mint can only specify the", "number of decimals.", "", "Fails on an invalid mint.", "", "Return data can be fetched using `sol_get_return_data` and deserialized", "with `String::from_utf8`." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The mint to calculate for."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 23 } }, { "kind": "instructionArgumentNode", "name": "amount", "docs": ["The amount of tokens to reformat."], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "uiAmountToAmount", "docs": [ "Convert a UiAmount of tokens to a little-endian `u64` raw Amount, using", "the given mint. In this version of the program, the mint can only", "specify the number of decimals.", "", "Return data can be fetched using `sol_get_return_data` and deserializing", "the return data as a little-endian `u64`." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The mint to calculate for."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 24 } }, { "kind": "instructionArgumentNode", "name": "uiAmount", "docs": ["The ui_amount of tokens to reformat."], "type": { "kind": "stringTypeNode", "encoding": "utf8" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "initializeMintCloseAuthority", "docs": [ "Initialize the close account authority on a new mint.", "", "Fails if the mint has already been initialized, so must be called before `InitializeMint`.", "", "The mint must have exactly enough space allocated for the base mint (82", "bytes), plus 83 bytes of padding, 1 byte reserved for the account type,", "then space required for this extension, plus any others." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The mint to initialize."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 25 } }, { "kind": "instructionArgumentNode", "name": "closeAuthority", "docs": ["Authority that must sign the `CloseAccount` instruction on a mint."], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "publicKeyTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "initializeTransferFeeConfig", "docs": [ "Initialize the transfer fee on a new mint.", "", "Fails if the mint has already been initialized, so must be called before `InitializeMint`.", "", "The mint must have exactly enough space allocated for the base mint (82", "bytes), plus 83 bytes of padding, 1 byte reserved for the account type,", "then space required for this extension, plus any others." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The mint to initialize."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 26 } }, { "kind": "instructionArgumentNode", "name": "transferFeeDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 0 } }, { "kind": "instructionArgumentNode", "name": "transferFeeConfigAuthority", "docs": ["Pubkey that may update the fees."], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "publicKeyTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "instructionArgumentNode", "name": "withdrawWithheldAuthority", "docs": ["Withdraw instructions must be signed by this key."], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "publicKeyTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "instructionArgumentNode", "name": "transferFeeBasisPoints", "docs": [ "Amount of transfer collected as fees, expressed as basis points of the transfer amount." ], "type": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } }, { "kind": "instructionArgumentNode", "name": "maximumFee", "docs": ["Maximum fee assessed on transfers."], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "transferFeeDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "transferCheckedWithFee", "docs": [ "Transfer, providing expected mint information and fees.", "", "This instruction succeeds if the mint has no configured transfer fee", "and the provided fee is 0. This allows applications to use", "`TransferCheckedWithFee` with any mint." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "source", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The source account. May include the `TransferFeeAmount` extension."] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The token mint. May include the `TransferFeeConfig` extension."] }, { "kind": "instructionAccountNode", "name": "destination", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The destination account. May include the `TransferFeeAmount` extension."] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The source account's owner/delegate or its multisignature account."], "defaultValue": { "kind": "identityValueNode" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 26 } }, { "kind": "instructionArgumentNode", "name": "transferFeeDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } }, { "kind": "instructionArgumentNode", "name": "amount", "docs": ["The amount of tokens to transfer."], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, { "kind": "instructionArgumentNode", "name": "decimals", "docs": ["Expected number of base 10 digits to the right of the decimal place."], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, { "kind": "instructionArgumentNode", "name": "fee", "docs": [ "Expected fee assessed on this transfer, calculated off-chain based", "on the transfer_fee_basis_points and maximum_fee of the mint. May", "be 0 for a mint without a configured transfer fee." ], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "transferFeeDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "withdrawWithheldTokensFromMint", "docs": [ "Transfer all withheld tokens in the mint to an account. Signed by the", "mint's withdraw withheld tokens authority." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The token mint. Must include the `TransferFeeConfig` extension."] }, { "kind": "instructionAccountNode", "name": "feeReceiver", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [ "The fee receiver account. Must include the `TransferFeeAmount`", "extension associated with the provided mint." ] }, { "kind": "instructionAccountNode", "name": "withdrawWithheldAuthority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The mint's `withdraw_withheld_authority` or its multisignature account."], "defaultValue": { "kind": "identityValueNode" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 26 } }, { "kind": "instructionArgumentNode", "name": "transferFeeDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 2 } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "transferFeeDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "withdrawWithheldTokensFromAccounts", "docs": [ "Transfer all withheld tokens to an account. Signed by the mint's", "withdraw withheld tokens authority." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The token mint. Must include the `TransferFeeConfig` extension."] }, { "kind": "instructionAccountNode", "name": "feeReceiver", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [ "The fee receiver account. Must include the `TransferFeeAmount`", "extension associated with the provided mint." ] }, { "kind": "instructionAccountNode", "name": "withdrawWithheldAuthority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The mint's `withdraw_withheld_authority` or its multisignature account."], "defaultValue": { "kind": "identityValueNode" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 26 } }, { "kind": "instructionArgumentNode", "name": "transferFeeDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 3 } }, { "kind": "instructionArgumentNode", "name": "numTokenAccounts", "docs": ["Number of token accounts harvested."], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } }, { "kind": "instructionRemainingAccountsNode", "isOptional": false, "isWritable": true, "isSigner": false, "docs": ["The source accounts to withdraw from."], "value": { "kind": "argumentValueNode", "name": "sources" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "transferFeeDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "harvestWithheldTokensToMint", "docs": [ "Permissionless instruction to transfer all withheld tokens to the mint.", "", "Succeeds for frozen accounts.", "", "Accounts provided should include the `TransferFeeAmount` extension.", "If not, the account is skipped." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The token mint."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 26 } }, { "kind": "instructionArgumentNode", "name": "transferFeeDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 4 } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": false, "isWritable": true, "isSigner": false, "docs": ["The source accounts to harvest from."], "value": { "kind": "argumentValueNode", "name": "sources" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "transferFeeDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "setTransferFee", "docs": [ "Set transfer fee. Only supported for mints that include the", "`TransferFeeConfig` extension." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The mint."] }, { "kind": "instructionAccountNode", "name": "transferFeeConfigAuthority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The mint's fee account owner or its multisignature account."], "defaultValue": { "kind": "identityValueNode" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 26 } }, { "kind": "instructionArgumentNode", "name": "transferFeeDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 5 } }, { "kind": "instructionArgumentNode", "name": "transferFeeBasisPoints", "docs": [ "Amount of transfer collected as fees, expressed as basis points of the transfer amount." ], "type": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } }, { "kind": "instructionArgumentNode", "name": "maximumFee", "docs": ["Maximum fee assessed on transfers."], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "transferFeeDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "initializeConfidentialTransferMint", "docs": [ "Initializes confidential transfers for a mint.", "", "The `ConfidentialTransferInstruction::InitializeMint` instruction", "requires no signers and MUST be included within the same Transaction", "as `TokenInstruction::InitializeMint`. Otherwise another party can", "initialize the configuration.", "", "The instruction fails if the `TokenInstruction::InitializeMint`", "instruction has already executed for the mint." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The SPL Token mint."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 27 } }, { "kind": "instructionArgumentNode", "name": "confidentialTransferDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 0 } }, { "kind": "instructionArgumentNode", "name": "authority", "docs": [ "Authority to modify the `ConfidentialTransferMint` configuration and to", "approve new accounts." ], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } }, { "kind": "instructionArgumentNode", "name": "autoApproveNewAccounts", "docs": [ "Determines if newly configured accounts must be approved by the", "`authority` before they may be used by the user." ], "type": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "instructionArgumentNode", "name": "auditorElgamalPubkey", "docs": ["New authority to decode any transfer amount in a confidential transfer."], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "confidentialTransferDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "updateConfidentialTransferMint", "docs": [ "Updates the confidential transfer mint configuration for a mint.", "", "Use `TokenInstruction::SetAuthority` to update the confidential transfer", "mint authority." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The SPL Token mint."] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Confidential transfer mint authority."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 27 } }, { "kind": "instructionArgumentNode", "name": "confidentialTransferDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } }, { "kind": "instructionArgumentNode", "name": "autoApproveNewAccounts", "docs": [ "Determines if newly configured accounts must be approved by the", "`authority` before they may be used by the user." ], "type": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "instructionArgumentNode", "name": "auditorElgamalPubkey", "docs": ["New authority to decode any transfer amount in a confidential transfer."], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "confidentialTransferDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "configureConfidentialTransferAccount", "docs": [ "Configures confidential transfers for a token account.", "", "The instruction fails if the confidential transfers are already", "configured, or if the mint was not initialized with confidential", "transfer support.", "", "The instruction fails if the `TokenInstruction::InitializeAccount`", "instruction has not yet successfully executed for the token account.", "", "Upon success, confidential and non-confidential deposits and transfers", "are enabled. Use the `DisableConfidentialCredits` and", "`DisableNonConfidentialCredits` instructions to disable.", "", "In order for this instruction to be successfully processed, it must be", "accompanied by the `VerifyPubkeyValidity` instruction of the", "`zk_elgamal_proof` program in the same transaction or the address of a", "context state account for the proof must be provided." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The SPL Token account."] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The corresponding SPL Token mint."] }, { "kind": "instructionAccountNode", "name": "instructionsSysvarOrContextState", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [ "Instructions sysvar if `VerifyPubkeyValidity` is included in", "the same transaction or context state account if", "`VerifyPubkeyValidity` is pre-verified into a context state", "account." ], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "record", "isWritable": false, "isSigner": false, "isOptional": true, "docs": [ "(Optional) Record account if the accompanying proof is to be read from a record account." ] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The source account's owner/delegate or its multisignature account."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 27 } }, { "kind": "instructionArgumentNode", "name": "confidentialTransferDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 2 } }, { "kind": "instructionArgumentNode", "name": "decryptableZeroBalance", "docs": ["The decryptable balance (always 0) once the configure account succeeds."], "type": { "kind": "definedTypeLinkNode", "name": "decryptableBalance" } }, { "kind": "instructionArgumentNode", "name": "maximumPendingBalanceCreditCounter", "docs": [ "The maximum number of despots and transfers that an account can receiver", "before the `ApplyPendingBalance` is executed" ], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, { "kind": "instructionArgumentNode", "name": "proofInstructionOffset", "docs": [ "Relative location of the `ProofInstruction::ZeroCiphertextProof`", "instruction to the `ConfigureAccount` instruction in the", "transaction. If the offset is `0`, then use a context state account", "for the proof." ], "type": { "kind": "numberTypeNode", "format": "i8", "endian": "le" } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "confidentialTransferDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "approveConfidentialTransferAccount", "docs": [ "Approves a token account for confidential transfers.", "", "Approval is only required when the", "`ConfidentialTransferMint::approve_new_accounts` field is set in the", "SPL Token mint. This instruction must be executed after the account", "owner configures their account for confidential transfers with", "`ConfidentialTransferInstruction::ConfigureAccount`." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The SPL Token account to approve."] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The corresponding SPL Token mint."] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Confidential transfer mint authority."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 27 } }, { "kind": "instructionArgumentNode", "name": "confidentialTransferDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 3 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "confidentialTransferDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "emptyConfidentialTransferAccount", "docs": [ "Empty the available balance in a confidential token account.", "", "A token account that is extended for confidential transfers can only be", "closed if the pending and available balance ciphertexts are emptied.", "The pending balance can be emptied", "via the `ConfidentialTransferInstruction::ApplyPendingBalance`", "instruction. Use the `ConfidentialTransferInstruction::EmptyAccount`", "instruction to empty the available balance ciphertext.", "", "Note that a newly configured account is always empty, so this", "instruction is not required prior to account closing if no", "instructions beyond", "`ConfidentialTransferInstruction::ConfigureAccount` have affected the", "token account.", "", "In order for this instruction to be successfully processed, it must be", "accompanied by the `VerifyZeroCiphertext` instruction of the", "`zk_elgamal_proof` program in the same transaction or the address of a", "context state account for the proof must be provided." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The SPL Token account."] }, { "kind": "instructionAccountNode", "name": "instructionsSysvarOrContextState", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [ "Instructions sysvar if `VerifyZeroCiphertext` is included in", "the same transaction or context state account if", "`VerifyZeroCiphertext` is pre-verified into a context state", "account." ], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "Sysvar1nstructions1111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "record", "isWritable": false, "isSigner": false, "isOptional": true, "docs": [ "(Optional) Record account if the accompanying proof is to be read from a record account." ] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The source account's owner/delegate or its multisignature account."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 27 } }, { "kind": "instructionArgumentNode", "name": "confidentialTransferDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 4 } }, { "kind": "instructionArgumentNode", "name": "proofInstructionOffset", "docs": [ "Relative location of the `ProofInstruction::VerifyCloseAccount`", "instruction to the `EmptyAccount` instruction in the transaction. If", "the offset is `0`, then use a context state account for the proof." ], "type": { "kind": "numberTypeNode", "format": "i8", "endian": "le" } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "confidentialTransferDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "confidentialDeposit", "docs": [ "Deposit SPL Tokens into the pending balance of a confidential token", "account.", "", "The account owner can then invoke the `ApplyPendingBalance` instruction", "to roll the deposit into their available balance at a time of their", "choosing.", "", "Fails if the source or destination accounts are frozen.", "Fails if the associated mint is extended as `NonTransferable`." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The SPL Token account."] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The corresponding SPL Token mint."] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The source account's owner/delegate or its multisignature account."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 27 } }, { "kind": "instructionArgumentNode", "name": "confidentialTransferDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 5 } }, { "kind": "instructionArgumentNode", "name": "amount", "docs": ["The amount of tokens to deposit."], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, { "kind": "instructionArgumentNode", "name": "decimals", "docs": ["Expected number of base 10 digits to the right of the decimal place."], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "confidentialTransferDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "confidentialWithdraw", "docs": [ "Withdraw SPL Tokens from the available balance of a confidential token", "account.", "", "In order for this instruction to be successfully processed, it must be", "accompanied by the following list of `zk_elgamal_proof` program", "instructions:", "- `VerifyCiphertextCommitmentEquality`", "- `VerifyBatchedRangeProofU64`", "These instructions can be accompanied in the same transaction or can be", "pre-verified into a context state account, in which case, only their", "context state account address need to be provided.", "", "Fails if the source or destination accounts are frozen.", "Fails if the associated mint is extended as `NonTransferable`." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The SPL Token account."] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The corresponding SPL Token mint."] }, { "kind": "instructionAccountNode", "name": "instructionsSysvar", "isWritable": false, "isSigner": false, "isOptional": true, "docs": [ "Instructions sysvar if at least one of the", "`zk_elgamal_proof` instructions are included in the same", "transaction." ] }, { "kind": "instructionAccountNode", "name": "equalityRecord", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["(Optional) Equality proof record account or context state account."] }, { "kind": "instructionAccountNode", "name": "rangeRecord", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["(Optional) Range proof record account or context state account."] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The source account's owner/delegate or its multisignature account."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 27 } }, { "kind": "instructionArgumentNode", "name": "confidentialTransferDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 6 } }, { "kind": "instructionArgumentNode", "name": "amount", "docs": ["The amount of tokens to withdraw."], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, { "kind": "instructionArgumentNode", "name": "decimals", "docs": ["Expected number of base 10 digits to the right of the decimal place."], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, { "kind": "instructionArgumentNode", "name": "newDecryptableAvailableBalance", "docs": ["The new decryptable balance if the withdrawal succeeds."], "type": { "kind": "definedTypeLinkNode", "name": "decryptableBalance" } }, { "kind": "instructionArgumentNode", "name": "equalityProofInstructionOffset", "docs": [ "Relative location of the", "`ProofInstruction::VerifyCiphertextCommitmentEquality` instruction", "to the `Withdraw` instruction in the transaction. If the offset is", "`0`, then use a context state account for the proof." ], "type": { "kind": "numberTypeNode", "format": "i8", "endian": "le" } }, { "kind": "instructionArgumentNode", "name": "rangeProofInstructionOffset", "docs": [ "Relative location of the `ProofInstruction::BatchedRangeProofU64`", "instruction to the `Withdraw` instruction in the transaction. If the", "offset is `0`, then use a context state account for the proof." ], "type": { "kind": "numberTypeNode", "format": "i8", "endian": "le" } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "confidentialTransferDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "confidentialTransfer", "docs": [ "Transfer tokens confidentially.", "", "In order for this instruction to be successfully processed, it must be", "accompanied by the following list of `zk_elgamal_proof` program", "instructions:", "- `VerifyCiphertextCommitmentEquality`", "- `VerifyBatchedGroupedCiphertext3HandlesValidity`", "- `VerifyBatchedRangeProofU128`", "These instructions can be accompanied in the same transaction or can be", "pre-verified into a context state account, in which case, only their", "context state account addresses need to be provided.", "", "Fails if the associated mint is extended as `NonTransferable`." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "sourceToken", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The source SPL Token account."] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The corresponding SPL Token mint."] }, { "kind": "instructionAccountNode", "name": "destinationToken", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The destination SPL Token account."] }, { "kind": "instructionAccountNode", "name": "instructionsSysvar", "isWritable": false, "isSigner": false, "isOptional": true, "docs": [ "(Optional) Instructions sysvar if at least one of the", "`zk_elgamal_proof` instructions are included in the same", "transaction." ] }, { "kind": "instructionAccountNode", "name": "equalityRecord", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["(Optional) Equality proof record account or context state account."] }, { "kind": "instructionAccountNode", "name": "ciphertextValidityRecord", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["(Optional) Ciphertext validity proof record account or context state account."] }, { "kind": "instructionAccountNode", "name": "rangeRecord", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["(Optional) Range proof record account or context state account."] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The source account's owner/delegate or its multisignature account."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 27 } }, { "kind": "instructionArgumentNode", "name": "confidentialTransferDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 7 } }, { "kind": "instructionArgumentNode", "name": "newSourceDecryptableAvailableBalance", "docs": ["The new source decryptable balance if the transfer succeeds."], "type": { "kind": "definedTypeLinkNode", "name": "decryptableBalance" } }, { "kind": "instructionArgumentNode", "name": "equalityProofInstructionOffset", "docs": [ "Relative location of the", "`ProofInstruction::VerifyCiphertextCommitmentEquality` instruction", "to the `Transfer` instruction in the transaction. If the offset is", "`0`, then use a context state account for the proof." ], "type": { "kind": "numberTypeNode", "format": "i8", "endian": "le" } }, { "kind": "instructionArgumentNode", "name": "ciphertextValidityProofInstructionOffset", "docs": [ "Relative location of the", "`ProofInstruction::VerifyBatchedGroupedCiphertext3HandlesValidity`", "instruction to the `Transfer` instruction in the transaction. If the", "offset is `0`, then use a context state account for the proof." ], "type": { "kind": "numberTypeNode", "format": "i8", "endian": "le" } }, { "kind": "instructionArgumentNode", "name": "rangeProofInstructionOffset", "docs": [ "Relative location of the `ProofInstruction::BatchedRangeProofU128Data`", "instruction to the `Transfer` instruction in the transaction. If the", "offset is `0`, then use a context state account for the proof." ], "type": { "kind": "numberTypeNode", "format": "i8", "endian": "le" } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "confidentialTransferDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "applyConfidentialPendingBalance", "docs": [ "Applies the pending balance to the available balance, based on the", "history of `Deposit` and/or `Transfer` instructions.", "", "After submitting `ApplyPendingBalance`, the client should compare", "`ConfidentialTransferAccount::expected_pending_balance_credit_counter`", "with", "`ConfidentialTransferAccount::actual_applied_pending_balance_instructions`. If they are", "equal then the", "`ConfidentialTransferAccount::decryptable_available_balance` is", "consistent with `ConfidentialTransferAccount::available_balance`. If", "they differ then there is more pending balance to be applied." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The SPL Token account."] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The source account's owner/delegate or its multisignature account."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 27 } }, { "kind": "instructionArgumentNode", "name": "confidentialTransferDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 8 } }, { "kind": "instructionArgumentNode", "name": "expectedPendingBalanceCreditCounter", "docs": [ "The expected number of pending balance credits since the last successful", "`ApplyPendingBalance` instruction" ], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, { "kind": "instructionArgumentNode", "name": "newDecryptableAvailableBalance", "docs": ["The new decryptable balance if the pending balance is applied", "successfully"], "type": { "kind": "definedTypeLinkNode", "name": "decryptableBalance" } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "confidentialTransferDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "enableConfidentialCredits", "docs": ["Configure a confidential extension account to accept incoming", "confidential transfers."], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The SPL Token account."] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The source account's owner/delegate or its multisignature account."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 27 } }, { "kind": "instructionArgumentNode", "name": "confidentialTransferDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 9 } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "confidentialTransferDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "disableConfidentialCredits", "docs": [ "Configure a confidential extension account to reject any incoming", "confidential transfers.", "", "If the `allow_non_confidential_credits` field is `true`, then the base", "account can still receive non-confidential transfers.", "", "This instruction can be used to disable confidential payments after a", "token account has already been extended for confidential transfers." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The SPL Token account."] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The source account's owner/delegate or its multisignature account."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 27 } }, { "kind": "instructionArgumentNode", "name": "confidentialTransferDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 10 } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "confidentialTransferDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "enableNonConfidentialCredits", "docs": [ "Configure an account with the confidential extension to accept incoming", "non-confidential transfers." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The SPL Token account."] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The source account's owner/delegate or its multisignature account."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 27 } }, { "kind": "instructionArgumentNode", "name": "confidentialTransferDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 11 } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "confidentialTransferDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "disableNonConfidentialCredits", "docs": [ "Configure an account with the confidential extension to reject any", "incoming non-confidential transfers.", "", "This instruction can be used to configure a confidential extension", "account to exclusively receive confidential payments." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The SPL Token account."] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The source account's owner/delegate or its multisignature account."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 27 } }, { "kind": "instructionArgumentNode", "name": "confidentialTransferDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 12 } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "confidentialTransferDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "confidentialTransferWithFee", "docs": [ "Transfer tokens confidentially with fee.", "", "In order for this instruction to be successfully processed, it must be", "accompanied by the following list of `zk_elgamal_proof` program", "instructions:", "- `VerifyCiphertextCommitmentEquality`", "- `VerifyBatchedGroupedCiphertext3HandlesValidity` (transfer amount", " ciphertext)", "- `VerifyPercentageWithFee`", "- `VerifyBatchedGroupedCiphertext2HandlesValidity` (fee ciphertext)", "- `VerifyBatchedRangeProofU256`", "These instructions can be accompanied in the same transaction or can be", "pre-verified into a context state account, in which case, only their", "context state account addresses need to be provided.", "", "The same restrictions for the `Transfer` applies to", "`TransferWithFee`. Namely, the instruction fails if the", "associated mint is extended as `NonTransferable`." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "sourceToken", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The source SPL Token account."] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The corresponding SPL Token mint."] }, { "kind": "instructionAccountNode", "name": "destinationToken", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The destination SPL Token account."] }, { "kind": "instructionAccountNode", "name": "instructionsSysvar", "isWritable": false, "isSigner": false, "isOptional": true, "docs": [ "(Optional) Instructions sysvar if at least one of the", "`zk_elgamal_proof` instructions are included in the same", "transaction." ] }, { "kind": "instructionAccountNode", "name": "equalityRecord", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["(Optional) Equality proof record account or context state account."] }, { "kind": "instructionAccountNode", "name": "transferAmountCiphertextValidityRecord", "isWritable": false, "isSigner": false, "isOptional": true, "docs": [ "(Optional) Transfer amount ciphertext validity proof record", "account or context state account." ] }, { "kind": "instructionAccountNode", "name": "feeSigmaRecord", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["(Optional) Fee sigma proof record account or context state account."] }, { "kind": "instructionAccountNode", "name": "feeCiphertextValidityRecord", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["(Optional) Fee ciphertext validity proof record account or context state account."] }, { "kind": "instructionAccountNode", "name": "rangeRecord", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["(Optional) Range proof record account or context state account."] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The source account's owner/delegate or its multisignature account."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 27 } }, { "kind": "instructionArgumentNode", "name": "confidentialTransferDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 13 } }, { "kind": "instructionArgumentNode", "name": "newSourceDecryptableAvailableBalance", "docs": ["The new source decryptable balance if the transfer succeeds."], "type": { "kind": "definedTypeLinkNode", "name": "decryptableBalance" } }, { "kind": "instructionArgumentNode", "name": "equalityProofInstructionOffset", "docs": [ "Relative location of the", "`ProofInstruction::VerifyCiphertextCommitmentEquality` instruction", "to the `TransferWithFee` instruction in the transaction. If the offset", "is `0`, then use a context state account for the proof." ], "type": { "kind": "numberTypeNode", "format": "i8", "endian": "le" } }, { "kind": "instructionArgumentNode", "name": "transferAmountCiphertextValidityProofInstructionOffset", "docs": [ "Relative location of the", "`ProofInstruction::VerifyBatchedGroupedCiphertext3HandlesValidity`", "instruction to the `TransferWithFee` instruction in the transaction.", "If the offset is `0`, then use a context state account for the", "proof." ], "type": { "kind": "numberTypeNode", "format": "i8", "endian": "le" } }, { "kind": "instructionArgumentNode", "name": "feeSigmaProofInstructionOffset", "docs": [ "Relative location of the `ProofInstruction::VerifyPercentageWithFee`", "instruction to the `TransferWithFee` instruction in the transaction.", "If the offset is `0`, then use a context state account for the", "proof." ], "type": { "kind": "numberTypeNode", "format": "i8", "endian": "le" } }, { "kind": "instructionArgumentNode", "name": "feeCiphertextValidityProofInstructionOffset", "docs": [ "Relative location of the", "`ProofInstruction::VerifyBatchedGroupedCiphertext2HandlesValidity`", "instruction to the `TransferWithFee` instruction in the transaction.", "If the offset is `0`, then use a context state account for the", "proof." ], "type": { "kind": "numberTypeNode", "format": "i8", "endian": "le" } }, { "kind": "instructionArgumentNode", "name": "rangeProofInstructionOffset", "docs": [ "Relative location of the `ProofInstruction::BatchedRangeProofU256Data`", "instruction to the `TransferWithFee` instruction in the transaction.", "If the offset is `0`, then use a context state account for the", "proof." ], "type": { "kind": "numberTypeNode", "format": "i8", "endian": "le" } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "confidentialTransferDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "initializeDefaultAccountState", "docs": [ "Initialize a new mint with the default state for new Accounts.", "", "Fails if the mint has already been initialized, so must be called before", "`InitializeMint`.", "", "The mint must have exactly enough space allocated for the base mint (82", "bytes), plus 83 bytes of padding, 1 byte reserved for the account type,", "then space required for this extension, plus any others." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The mint."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 28 } }, { "kind": "instructionArgumentNode", "name": "defaultAccountStateDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 0 } }, { "kind": "instructionArgumentNode", "name": "state", "docs": ["The state each new token account should start with."], "type": { "kind": "definedTypeLinkNode", "name": "accountState" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "defaultAccountStateDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "updateDefaultAccountState", "docs": [ "Update the default state for new Accounts. Only supported for mints that", "include the `DefaultAccountState` extension." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The mint."] }, { "kind": "instructionAccountNode", "name": "freezeAuthority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The mint freeze authority or its multisignature account."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 28 } }, { "kind": "instructionArgumentNode", "name": "defaultAccountStateDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } }, { "kind": "instructionArgumentNode", "name": "state", "docs": ["The state each new token account should start with."], "type": { "kind": "definedTypeLinkNode", "name": "accountState" } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "defaultAccountStateDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "reallocate", "docs": [ "Check to see if a token account is large enough for a list of", "ExtensionTypes, and if not, use reallocation to increase the data", "size." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The token account to reallocate."] }, { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["The payer account to fund reallocation."] }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program for reallocation funding."], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "owner", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The account's owner or its multisignature account."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 29 } }, { "kind": "instructionArgumentNode", "name": "newExtensionTypes", "docs": ["New extension types to include in the reallocated account."], "type": { "kind": "arrayTypeNode", "item": { "kind": "definedTypeLinkNode", "name": "extensionType" }, "count": { "kind": "remainderCountNode" } } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "enableMemoTransfers", "docs": [ "Require memos for transfers into this Account. Adds the MemoTransfer", "extension to the Account, if it doesn't already exist." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The token account to update."] }, { "kind": "instructionAccountNode", "name": "owner", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The account's owner or its multisignature account."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 30 } }, { "kind": "instructionArgumentNode", "name": "memoTransfersDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 0 } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "memoTransfersDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "disableMemoTransfers", "docs": [ "Stop requiring memos for transfers into this Account.", "", "Implicitly initializes the extension in the case where it is not", "present." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The token account to update."] }, { "kind": "instructionAccountNode", "name": "owner", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The account's owner or its multisignature account."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 30 } }, { "kind": "instructionArgumentNode", "name": "memoTransfersDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "memoTransfersDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "createNativeMint", "docs": [ "Creates the native mint.", "", "This instruction only needs to be invoked once after deployment and is", "permissionless. Wrapped SOL (`native_mint::id()`) will not be", "available until this instruction is successfully executed." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Funding account (must be a system account)"] }, { "kind": "instructionAccountNode", "name": "nativeMint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The native mint address"] }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program for mint account funding"], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 31 } } ], "remainingAccounts": [], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "initializeNonTransferableMint", "docs": [ "Initialize the non transferable extension for the given mint account", "", "Fails if the account has already been initialized, so must be called before `InitializeMint`." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The mint account to initialize."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 32 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "initializeInterestBearingMint", "docs": [ "Initialize a new mint with the `InterestBearing` extension.", "", "Fails if the mint has already been initialized, so must be called before", "`InitializeMint`.", "", "The mint must have exactly enough space allocated for the base mint (82", "bytes), plus 83 bytes of padding, 1 byte reserved for the account type,", "then space required for this extension, plus any others." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The mint to initialize."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 33 } }, { "kind": "instructionArgumentNode", "name": "interestBearingMintDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 0 } }, { "kind": "instructionArgumentNode", "name": "rateAuthority", "docs": ["The public key for the account that can update the rate"], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } }, { "kind": "instructionArgumentNode", "name": "rate", "docs": ["The initial interest rate"], "type": { "kind": "numberTypeNode", "format": "i16", "endian": "le" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "interestBearingMintDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "updateRateInterestBearingMint", "docs": [ "Update the interest rate. Only supported for mints that include the", "`InterestBearingConfig` extension." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The mint."] }, { "kind": "instructionAccountNode", "name": "rateAuthority", "isWritable": true, "isSigner": "either", "isOptional": false, "docs": ["The mint rate authority."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 33 } }, { "kind": "instructionArgumentNode", "name": "interestBearingMintDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } }, { "kind": "instructionArgumentNode", "name": "rate", "docs": ["The interest rate to update."], "type": { "kind": "numberTypeNode", "format": "i16", "endian": "le" } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "interestBearingMintDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "enableCpiGuard", "docs": [ "Lock certain token operations from taking place within CPI for this Account, namely:", "* Transfer and Burn must go through a delegate.", "* CloseAccount can only return lamports to owner.", "* SetAuthority can only be used to remove an existing close authority.", "* Approve is disallowed entirely.", "", "In addition, CPI Guard cannot be enabled or disabled via CPI." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The token account to update."] }, { "kind": "instructionAccountNode", "name": "owner", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The account's owner/delegate or its multisignature account."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 34 } }, { "kind": "instructionArgumentNode", "name": "cpiGuardDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 0 } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "cpiGuardDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "disableCpiGuard", "docs": [ "Allow all token operations to happen via CPI as normal.", "", "Implicitly initializes the extension in the case where it is not present." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The token account to update."] }, { "kind": "instructionAccountNode", "name": "owner", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The account's owner/delegate or its multisignature account."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 34 } }, { "kind": "instructionArgumentNode", "name": "cpiGuardDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "cpiGuardDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "initializePermanentDelegate", "docs": [ "Initialize the permanent delegate on a new mint.", "", "Fails if the mint has already been initialized, so must be called before `InitializeMint`.", "", "The mint must have exactly enough space allocated for the base mint (82 bytes),", "plus 83 bytes of padding, 1 byte reserved for the account type,", "then space required for this extension, plus any others." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The mint to initialize."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 35 } }, { "kind": "instructionArgumentNode", "name": "delegate", "docs": ["Authority that may sign for `Transfer`s and `Burn`s on any account"], "type": { "kind": "publicKeyTypeNode" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "initializeTransferHook", "docs": [ "Initialize a new mint with a transfer hook program.", "", "Fails if the mint has already been initialized, so must be called before `InitializeMint`.", "", "The mint must have exactly enough space allocated for the base mint (82 bytes),", "plus 83 bytes of padding, 1 byte reserved for the account type,", "then space required for this extension, plus any others." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The mint to initialize."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 36 } }, { "kind": "instructionArgumentNode", "name": "transferHookDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 0 } }, { "kind": "instructionArgumentNode", "name": "authority", "docs": ["The public key for the account that can update the program id"], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } }, { "kind": "instructionArgumentNode", "name": "programId", "docs": ["The program id that performs logic during transfers"], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "transferHookDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "updateTransferHook", "docs": [ "Update the transfer hook program id. Only supported for mints that", "include the `TransferHook` extension.", "", "Accounts expected by this instruction:", "", " 0. `[writable]` The mint.", " 1. `[signer]` The transfer hook authority." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The mint."] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The transfer hook authority."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 36 } }, { "kind": "instructionArgumentNode", "name": "transferHookDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } }, { "kind": "instructionArgumentNode", "name": "programId", "docs": ["The program id that performs logic during transfers"], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "transferHookDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "initializeConfidentialTransferFee", "docs": [ "Initializes confidential transfer fees for a mint.", "", "The instruction must be included within the same Transaction as TokenInstruction::InitializeMint.", "Otherwise another party can initialize the configuration.", "", "The instruction fails if TokenInstruction::InitializeMint has already executed for the mint." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The SPL Token mint."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 37 } }, { "kind": "instructionArgumentNode", "name": "confidentialTransferFeeDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 0 } }, { "kind": "instructionArgumentNode", "name": "authority", "docs": ["Optional authority to set the withdraw withheld authority ElGamal key"], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } }, { "kind": "instructionArgumentNode", "name": "withdrawWithheldAuthorityElGamalPubkey", "docs": ["Withheld fees from accounts must be encrypted with this ElGamal key"], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "confidentialTransferFeeDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "withdrawWithheldTokensFromMintForConfidentialTransferFee", "docs": [ "Transfer all withheld confidential tokens in the mint to an account.", "Signed by the mint's withdraw withheld tokens authority.", "", "The withheld confidential tokens are aggregated directly into the destination available balance.", "", "Must be accompanied by the VerifyCiphertextCiphertextEquality instruction", "of the zk_elgamal_proof program in the same transaction or the address of", "a context state account for the proof must be provided." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The token mint."] }, { "kind": "instructionAccountNode", "name": "destination", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The fee receiver account."] }, { "kind": "instructionAccountNode", "name": "instructionsSysvarOrContextState", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar or context state account"] }, { "kind": "instructionAccountNode", "name": "record", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Optional record account if proof is read from record"] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The mint's withdraw_withheld_authority"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 37 } }, { "kind": "instructionArgumentNode", "name": "confidentialTransferFeeDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } }, { "kind": "instructionArgumentNode", "name": "proofInstructionOffset", "docs": ["Proof instruction offset"], "type": { "kind": "numberTypeNode", "format": "i8", "endian": "le" } }, { "kind": "instructionArgumentNode", "name": "newDecryptableAvailableBalance", "docs": ["The new decryptable balance in the destination token account"], "type": { "kind": "definedTypeLinkNode", "name": "decryptableBalance" } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "confidentialTransferFeeDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "withdrawWithheldTokensFromAccountsForConfidentialTransferFee", "docs": [ "Transfer all withheld tokens to an account. Signed by the mint's withdraw withheld", "tokens authority. This instruction is susceptible to front-running.", "Use `HarvestWithheldTokensToMint` and `WithdrawWithheldTokensFromMint` as alternative.", "", "Must be accompanied by the VerifyWithdrawWithheldTokens instruction." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The token mint."] }, { "kind": "instructionAccountNode", "name": "destination", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The fee receiver account."] }, { "kind": "instructionAccountNode", "name": "instructionsSysvarOrContextState", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Instructions sysvar or context state account"] }, { "kind": "instructionAccountNode", "name": "record", "isWritable": false, "isSigner": false, "isOptional": true, "docs": ["Optional record account"] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The mint's withdraw_withheld_authority"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 37 } }, { "kind": "instructionArgumentNode", "name": "confidentialTransferFeeDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 2 } }, { "kind": "instructionArgumentNode", "name": "numTokenAccounts", "docs": ["Number of token accounts harvested"], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, { "kind": "instructionArgumentNode", "name": "proofInstructionOffset", "docs": ["Proof instruction offset"], "type": { "kind": "numberTypeNode", "format": "i8", "endian": "le" } }, { "kind": "instructionArgumentNode", "name": "newDecryptableAvailableBalance", "docs": ["The new decryptable balance in the destination token account"], "type": { "kind": "definedTypeLinkNode", "name": "decryptableBalance" } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "confidentialTransferFeeDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "harvestWithheldTokensToMintForConfidentialTransferFee", "docs": [ "Permissionless instruction to transfer all withheld confidential tokens to the mint.", "", "Succeeds for frozen accounts.", "", "Accounts provided should include both the `TransferFeeAmount` and", "`ConfidentialTransferAccount` extension. If not, the account is skipped." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The mint."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 37 } }, { "kind": "instructionArgumentNode", "name": "confidentialTransferFeeDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 3 } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": false, "isWritable": true, "docs": ["The source accounts to harvest from"], "value": { "kind": "argumentValueNode", "name": "sources" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "confidentialTransferFeeDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "enableHarvestToMint", "docs": ["Configure a confidential transfer fee mint to accept harvested confidential fees."], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The token mint."] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The confidential transfer fee authority"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 37 } }, { "kind": "instructionArgumentNode", "name": "confidentialTransferFeeDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 4 } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "confidentialTransferFeeDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "disableHarvestToMint", "docs": ["Configure a confidential transfer fee mint to reject any harvested confidential fees."], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The token mint."] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The confidential transfer fee authority"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 37 } }, { "kind": "instructionArgumentNode", "name": "confidentialTransferFeeDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 5 } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "confidentialTransferFeeDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "withdrawExcessLamports", "docs": [ "This instruction is to be used to rescue SOLs sent to any TokenProgram", "owned account by sending them to any other account, leaving behind only", "lamports for rent exemption." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "sourceAccount", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Account holding excess lamports."] }, { "kind": "instructionAccountNode", "name": "destinationAccount", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Destination account for withdrawn lamports."] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The source account's owner/delegate or its multisignature account."], "defaultValue": { "kind": "identityValueNode" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 38 } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "initializeMetadataPointer", "docs": [ "Initialize a new mint with a metadata pointer", "", "Fails if the mint has already been initialized, so must be called before", "`InitializeMint`.", "", "The mint must have exactly enough space allocated for the base mint (82", "bytes), plus 83 bytes of padding, 1 byte reserved for the account type,", "then space required for this extension, plus any others." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The mint to initialize."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 39 } }, { "kind": "instructionArgumentNode", "name": "metadataPointerDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 0 } }, { "kind": "instructionArgumentNode", "name": "authority", "docs": ["The public key for the account that can update the metadata address."], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } }, { "kind": "instructionArgumentNode", "name": "metadataAddress", "docs": ["The account address that holds the metadata."], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "metadataPointerDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "updateMetadataPointer", "docs": [ "Update the metadata pointer address. Only supported for mints that", "include the `MetadataPointer` extension." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The mint to initialize."] }, { "kind": "instructionAccountNode", "name": "metadataPointerAuthority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The metadata pointer authority or its multisignature account."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 39 } }, { "kind": "instructionArgumentNode", "name": "metadataPointerDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } }, { "kind": "instructionArgumentNode", "name": "metadataAddress", "docs": ["The new account address that holds the metadata."], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "metadataPointerDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "initializeGroupPointer", "docs": [ "Initialize a new mint with a group pointer", "", "Fails if the mint has already been initialized, so must be called before", "`InitializeMint`.", "", "The mint must have exactly enough space allocated for the base mint (82", "bytes), plus 83 bytes of padding, 1 byte reserved for the account type,", "then space required for this extension, plus any others." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The mint to initialize."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 40 } }, { "kind": "instructionArgumentNode", "name": "groupPointerDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 0 } }, { "kind": "instructionArgumentNode", "name": "authority", "docs": ["The public key for the account that can update the group address."], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } }, { "kind": "instructionArgumentNode", "name": "groupAddress", "docs": ["The account address that holds the group."], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "groupPointerDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "updateGroupPointer", "docs": [ "Update the group pointer address. Only supported for mints that", "include the `GroupPointer` extension." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The mint to initialize."] }, { "kind": "instructionAccountNode", "name": "groupPointerAuthority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The group pointer authority or its multisignature account."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 40 } }, { "kind": "instructionArgumentNode", "name": "groupPointerDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } }, { "kind": "instructionArgumentNode", "name": "groupAddress", "docs": ["The new account address that holds the group configurations."], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "groupPointerDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "initializeGroupMemberPointer", "docs": [ "Initialize a new mint with a group member pointer", "", "Fails if the mint has already been initialized, so must be called before", "`InitializeMint`.", "", "The mint must have exactly enough space allocated for the base mint (82", "bytes), plus 83 bytes of padding, 1 byte reserved for the account type,", "then space required for this extension, plus any others." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The mint to initialize."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 41 } }, { "kind": "instructionArgumentNode", "name": "groupMemberPointerDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 0 } }, { "kind": "instructionArgumentNode", "name": "authority", "docs": ["The public key for the account that can update the group member address."], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } }, { "kind": "instructionArgumentNode", "name": "memberAddress", "docs": ["The account address that holds the member."], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "groupMemberPointerDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "updateGroupMemberPointer", "docs": [ "Update the group member pointer address. Only supported for mints that", "include the `GroupMemberPointer` extension." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The mint to initialize."] }, { "kind": "instructionAccountNode", "name": "groupMemberPointerAuthority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The group member pointer authority or its multisignature account."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 41 } }, { "kind": "instructionArgumentNode", "name": "groupMemberPointerDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } }, { "kind": "instructionArgumentNode", "name": "memberAddress", "docs": ["The new account address that holds the member."], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "groupMemberPointerDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "initializeScaledUiAmountMint", "docs": [ "Initialize a new mint with the `ScaledUiAmount` extension.", "", "Fails if the mint has already been initialized, so must be called before `InitializeMint`.", "", "The mint must have exactly enough space allocated for the base mint (82 bytes),", "plus 83 bytes of padding, 1 byte reserved for the account type,", "then space required for this extension, plus any others." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The mint to initialize."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 43 } }, { "kind": "instructionArgumentNode", "name": "scaledUiAmountMintDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 0 } }, { "kind": "instructionArgumentNode", "name": "authority", "docs": ["The authority that can update the multiplier"], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } }, { "kind": "instructionArgumentNode", "name": "multiplier", "docs": ["The initial multiplier for the scaled UI extension"], "type": { "kind": "numberTypeNode", "format": "f64", "endian": "le" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "scaledUiAmountMintDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "updateMultiplierScaledUiMint", "docs": [ "Update the multiplier. Only supported for mints that include the", "`ScaledUiAmountConfig` extension.", "You can set a specific timestamp for the multiplier to take effect." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The mint."] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": true, "isSigner": "either", "isOptional": false, "docs": ["The multiplier authority."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 43 } }, { "kind": "instructionArgumentNode", "name": "scaledUiAmountMintDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } }, { "kind": "instructionArgumentNode", "name": "multiplier", "docs": ["The new multiplier for the scaled UI extension"], "type": { "kind": "numberTypeNode", "format": "f64", "endian": "le" } }, { "kind": "instructionArgumentNode", "name": "effectiveTimestamp", "docs": ["The timestamp at which the new multiplier will take effect"], "type": { "kind": "numberTypeNode", "format": "i64", "endian": "le" } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "scaledUiAmountMintDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "initializePausableConfig", "docs": [ "Initialize a new mint with the `Pausable` extension.", "", "Fails if the mint has already been initialized, so must be called before `InitializeMint`." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The mint."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 44 } }, { "kind": "instructionArgumentNode", "name": "pausableDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 0 } }, { "kind": "instructionArgumentNode", "name": "authority", "docs": ["The authority that can pause and resume the mint."], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "pausableDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "pause", "docs": ["Pause the mint.", "", "Fails if the mint is not pausable."], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The mint."] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The pausable authority that can pause the mint."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 44 } }, { "kind": "instructionArgumentNode", "name": "pausableDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "pausableDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "resume", "docs": ["Resume the mint.", "", "Fails if the mint is not pausable."], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The mint."] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The pausable authority that can resume the mint."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 44 } }, { "kind": "instructionArgumentNode", "name": "pausableDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 2 } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "pausableDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "initializeTokenMetadata", "docs": [ "Initializes a TLV entry with the basic token-metadata fields.", "", "Assumes that the provided mint is an SPL token mint, that the metadata", "account is allocated and assigned to the program, and that the metadata", "account has enough lamports to cover the rent-exempt reserve." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "updateAuthority", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "mintAuthority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": [] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "bytesTypeNode" }, "defaultValue": { "kind": "bytesValueNode", "data": "d2e11ea258b84d8d", "encoding": "base16" } }, { "kind": "instructionArgumentNode", "name": "name", "docs": ["Longer name of the token."], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "instructionArgumentNode", "name": "symbol", "docs": ["Shortened symbol of the token."], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "instructionArgumentNode", "name": "uri", "docs": ["URI pointing to more metadata (image, video, etc.)."], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "updateTokenMetadataField", "docs": [ "Updates a field in a token-metadata account.", "", "The field can be one of the required fields (name, symbol, URI), or a", "totally new field denoted by a \"key\" string.", "", "By the end of the instruction, the metadata account must be properly", "resized based on the new size of the TLV entry.", " * If the new size is larger, the program must first reallocate to", " avoid", " overwriting other TLV entries.", " * If the new size is smaller, the program must reallocate at the end", " so that it's possible to iterate over TLV entries" ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "updateAuthority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": [] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "bytesTypeNode" }, "defaultValue": { "kind": "bytesValueNode", "data": "dde9312db5cadcc8", "encoding": "base16" } }, { "kind": "instructionArgumentNode", "name": "field", "docs": ["Field to update in the metadata."], "type": { "kind": "definedTypeLinkNode", "name": "tokenMetadataField" } }, { "kind": "instructionArgumentNode", "name": "value", "docs": ["Value to write for the field."], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "removeTokenMetadataKey", "docs": [ "Removes a key-value pair in a token-metadata account.", "", "This only applies to additional fields, and not the base name / symbol /", "URI fields.", "", "By the end of the instruction, the metadata account must be properly", "resized at the end based on the new size of the TLV entry." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "updateAuthority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": [] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "bytesTypeNode" }, "defaultValue": { "kind": "bytesValueNode", "data": "ea122038598d25b5", "encoding": "base16" } }, { "kind": "instructionArgumentNode", "name": "idempotent", "docs": [ "If the idempotent flag is set to true, then the instruction will not", "error if the key does not exist" ], "type": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "booleanValueNode", "boolean": false } }, { "kind": "instructionArgumentNode", "name": "key", "docs": ["Key to remove in the additional metadata portion."], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "updateTokenMetadataUpdateAuthority", "docs": ["Updates the token-metadata authority."], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "metadata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "updateAuthority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": [] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "bytesTypeNode" }, "defaultValue": { "kind": "bytesValueNode", "data": "d7e4a6e45464567b", "encoding": "base16" } }, { "kind": "instructionArgumentNode", "name": "newUpdateAuthority", "docs": ["New authority for the token metadata, or unset if `None`"], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "emitTokenMetadata", "docs": [ "Emits the token-metadata as return data", "", "The format of the data emitted follows exactly the `TokenMetadata`", "struct, but it's possible that the account data is stored in another", "format by the program.", "", "With this instruction, a program that implements the token-metadata", "interface can return `TokenMetadata` without adhering to the specific", "byte layout of the `TokenMetadata` struct in any accounts." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "metadata", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "bytesTypeNode" }, "defaultValue": { "kind": "bytesValueNode", "data": "faa6b4fa0d0cb846", "encoding": "base16" } }, { "kind": "instructionArgumentNode", "name": "start", "docs": ["Start of range of data to emit"], "type": { "kind": "optionTypeNode", "item": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } }, { "kind": "instructionArgumentNode", "name": "end", "docs": ["End of range of data to emit"], "type": { "kind": "optionTypeNode", "item": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "defaultValue": { "kind": "noneValueNode" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "initializeTokenGroup", "docs": ["Initialize a new `Group`", "", "Assumes one has already initialized a mint for the group."], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "group", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "mintAuthority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": [] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "bytesTypeNode" }, "defaultValue": { "kind": "bytesValueNode", "data": "79716c2736330004", "encoding": "base16" } }, { "kind": "instructionArgumentNode", "name": "updateAuthority", "docs": ["Update authority for the group"], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } }, { "kind": "instructionArgumentNode", "name": "maxSize", "docs": ["The maximum number of group members"], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "updateTokenGroupMaxSize", "docs": ["Update the max size of a `Group`."], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "group", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "updateAuthority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": [] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "bytesTypeNode" }, "defaultValue": { "kind": "bytesValueNode", "data": "6c25ab8ff81e126e", "encoding": "base16" } }, { "kind": "instructionArgumentNode", "name": "maxSize", "docs": ["New max size for the group"], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "updateTokenGroupUpdateAuthority", "docs": ["Update the authority of a `Group`."], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "group", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "updateAuthority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Current update authority"] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "bytesTypeNode" }, "defaultValue": { "kind": "bytesValueNode", "data": "a1695801edddd8cb", "encoding": "base16" } }, { "kind": "instructionArgumentNode", "name": "newUpdateAuthority", "docs": ["New authority for the group, or unset if `None`"], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "initializeTokenGroupMember", "docs": [ "Initialize a new `Member` of a `Group`", "", "Assumes the `Group` has already been initialized,", "as well as the mint for the member." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "member", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "memberMint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "memberMintAuthority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "group", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [] }, { "kind": "instructionAccountNode", "name": "groupUpdateAuthority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": [] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "bytesTypeNode" }, "defaultValue": { "kind": "bytesValueNode", "data": "9820deb0dfed7486", "encoding": "base16" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "unwrapLamports", "docs": ["Transfer lamports from a native SOL account to a destination account."], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "source", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The source account."] }, { "kind": "instructionAccountNode", "name": "destination", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The destination account."] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The source account's owner or its multisignature account."], "defaultValue": { "kind": "identityValueNode" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 45 } }, { "kind": "instructionArgumentNode", "name": "amount", "docs": ["The amount of lamports to transfer."], "type": { "kind": "optionTypeNode", "fixed": false, "item": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ] }, { "kind": "instructionNode", "name": "initializePermissionedBurn", "docs": [ "Require permissioned burn for the given mint account.", "", "Fails if the mint has already been initialized, so must be called before `InitializeMint`." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The mint account to initialize."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 46 } }, { "kind": "instructionArgumentNode", "name": "permissionedBurnDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 0 } }, { "kind": "instructionArgumentNode", "name": "authority", "docs": ["The public key for the account that is required for token burning."], "type": { "kind": "publicKeyTypeNode" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "permissionedBurnDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "permissionedBurn", "docs": ["Burn tokens when the mint has the permissioned burn extension enabled."], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "account", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The source account to burn from."] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The token mint."] }, { "kind": "instructionAccountNode", "name": "permissionedBurnAuthority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Authority configured on the mint that must sign any permissioned burn instruction."] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The account's owner/delegate or its multisignature account."], "defaultValue": { "kind": "identityValueNode" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 46 } }, { "kind": "instructionArgumentNode", "name": "permissionedBurnDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 1 } }, { "kind": "instructionArgumentNode", "name": "amount", "docs": ["The amount of tokens to burn."], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "permissionedBurnDiscriminator", "offset": 1 } ] }, { "kind": "instructionNode", "name": "permissionedBurnChecked", "docs": [ "Burn tokens with expected decimals when the mint has the permissioned burn extension enabled." ], "optionalAccountStrategy": "programId", "accounts": [ { "kind": "instructionAccountNode", "name": "account", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The source account to burn from."] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The token mint."] }, { "kind": "instructionAccountNode", "name": "permissionedBurnAuthority", "isWritable": false, "isSigner": true, "isOptional": false, "docs": ["Authority configured on the mint that must sign any permissioned burn instruction."] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The account's owner/delegate or its multisignature account."], "defaultValue": { "kind": "identityValueNode" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 46 } }, { "kind": "instructionArgumentNode", "name": "permissionedBurnDiscriminator", "defaultValueStrategy": "omitted", "docs": [], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "defaultValue": { "kind": "numberValueNode", "number": 2 } }, { "kind": "instructionArgumentNode", "name": "amount", "docs": ["The amount of tokens to burn."], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, { "kind": "instructionArgumentNode", "name": "decimals", "docs": ["Expected number of base 10 digits to the right of the decimal place."], "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "isOptional": true, "isSigner": true, "docs": [], "value": { "kind": "argumentValueNode", "name": "multiSigners" } } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 }, { "kind": "fieldDiscriminatorNode", "name": "permissionedBurnDiscriminator", "offset": 1 } ] } ], "definedTypes": [ { "kind": "definedTypeNode", "name": "accountState", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumEmptyVariantTypeNode", "name": "uninitialized" }, { "kind": "enumEmptyVariantTypeNode", "name": "initialized" }, { "kind": "enumEmptyVariantTypeNode", "name": "frozen" } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "authorityType", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumEmptyVariantTypeNode", "name": "mintTokens" }, { "kind": "enumEmptyVariantTypeNode", "name": "freezeAccount" }, { "kind": "enumEmptyVariantTypeNode", "name": "accountOwner" }, { "kind": "enumEmptyVariantTypeNode", "name": "closeAccount" }, { "kind": "enumEmptyVariantTypeNode", "name": "transferFeeConfig" }, { "kind": "enumEmptyVariantTypeNode", "name": "withheldWithdraw" }, { "kind": "enumEmptyVariantTypeNode", "name": "closeMint" }, { "kind": "enumEmptyVariantTypeNode", "name": "interestRate" }, { "kind": "enumEmptyVariantTypeNode", "name": "permanentDelegate" }, { "kind": "enumEmptyVariantTypeNode", "name": "confidentialTransferMint" }, { "kind": "enumEmptyVariantTypeNode", "name": "transferHookProgramId" }, { "kind": "enumEmptyVariantTypeNode", "name": "confidentialTransferFeeConfig" }, { "kind": "enumEmptyVariantTypeNode", "name": "metadataPointer" }, { "kind": "enumEmptyVariantTypeNode", "name": "groupPointer" }, { "kind": "enumEmptyVariantTypeNode", "name": "groupMemberPointer" }, { "kind": "enumEmptyVariantTypeNode", "name": "scaledUiAmount" }, { "kind": "enumEmptyVariantTypeNode", "name": "pause" }, { "kind": "enumEmptyVariantTypeNode", "name": "permissionedBurn" } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "transferFee", "docs": [], "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "epoch", "docs": ["First epoch where the transfer fee takes effect."], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "maximumFee", "docs": ["Maximum fee assessed on transfers, expressed as an amount of tokens."], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "transferFeeBasisPoints", "docs": [ "Amount of transfer collected as fees, expressed as basis points of the", "transfer amount, ie. increments of 0.01%." ], "type": { "kind": "amountTypeNode", "decimals": 2, "unit": "%", "number": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } } } ] } }, { "kind": "definedTypeNode", "name": "encryptedBalance", "docs": ["ElGamal ciphertext containing an account balance."], "type": { "kind": "fixedSizeTypeNode", "size": 64, "type": { "kind": "bytesTypeNode" } } }, { "kind": "definedTypeNode", "name": "decryptableBalance", "docs": ["Authenticated encryption containing an account balance."], "type": { "kind": "fixedSizeTypeNode", "size": 36, "type": { "kind": "bytesTypeNode" } } }, { "kind": "definedTypeNode", "name": "extension", "docs": [], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumEmptyVariantTypeNode", "name": "uninitialized" }, { "kind": "enumStructVariantTypeNode", "name": "transferFeeConfig", "struct": { "kind": "sizePrefixTypeNode", "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "transferFeeConfigAuthority", "docs": ["Optional authority to set the fee."], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "withdrawWithheldAuthority", "docs": ["Withdraw from mint instructions must be signed by this key."], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "withheldAmount", "docs": [ "Withheld transfer fee tokens that have been moved to the mint for withdrawal." ], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "olderTransferFee", "docs": [ "Older transfer fee, used if the current epoch < newerTransferFee.epoch." ], "type": { "kind": "definedTypeLinkNode", "name": "transferFee" } }, { "kind": "structFieldTypeNode", "name": "newerTransferFee", "docs": [ "Newer transfer fee, used if the current epoch >= newerTransferFee.epoch." ], "type": { "kind": "definedTypeLinkNode", "name": "transferFee" } } ] }, "prefix": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } } }, { "kind": "enumStructVariantTypeNode", "name": "transferFeeAmount", "struct": { "kind": "sizePrefixTypeNode", "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "withheldAmount", "docs": [ "Withheld transfer fee tokens that can be claimed by the fee authority." ], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } } ] }, "prefix": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } } }, { "kind": "enumStructVariantTypeNode", "name": "mintCloseAuthority", "struct": { "kind": "sizePrefixTypeNode", "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "closeAuthority", "docs": [], "type": { "kind": "publicKeyTypeNode" } } ] }, "prefix": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } } }, { "kind": "enumStructVariantTypeNode", "name": "confidentialTransferMint", "struct": { "kind": "sizePrefixTypeNode", "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "authority", "docs": [ "Authority to modify the `ConfidentialTransferMint` configuration and to", "approve new accounts (if `auto_approve_new_accounts` is true).", "", "The legacy Token Multisig account is not supported as the authority." ], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } }, { "kind": "structFieldTypeNode", "name": "autoApproveNewAccounts", "docs": [ "Indicate if newly configured accounts must be approved by the", "`authority` before they may be used by the user.", "", "* If `true`, no approval is required and new accounts may be used immediately.", "* If `false`, the authority must approve newly configured accounts (see", " `ConfidentialTransferInstruction::ConfigureAccount`)." ], "type": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "auditorElgamalPubkey", "docs": [ "Authority to decode any transfer amount in a confidential transfer." ], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } } ] }, "prefix": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } } }, { "kind": "enumStructVariantTypeNode", "name": "confidentialTransferAccount", "struct": { "kind": "sizePrefixTypeNode", "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "approved", "docs": [ "`true` if this account has been approved for use. All confidential", "transfer operations for the account will fail until approval is granted." ], "type": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "elgamalPubkey", "docs": ["The public key associated with ElGamal encryption."], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "pendingBalanceLow", "docs": [ "The low 16 bits of the pending balance (encrypted by `elgamal_pubkey`)." ], "type": { "kind": "definedTypeLinkNode", "name": "encryptedBalance" } }, { "kind": "structFieldTypeNode", "name": "pendingBalanceHigh", "docs": [ "The high 32 bits of the pending balance (encrypted by `elgamal_pubkey`)." ], "type": { "kind": "definedTypeLinkNode", "name": "encryptedBalance" } }, { "kind": "structFieldTypeNode", "name": "availableBalance", "docs": ["The available balance (encrypted by `encrypiton_pubkey`)."], "type": { "kind": "definedTypeLinkNode", "name": "encryptedBalance" } }, { "kind": "structFieldTypeNode", "name": "decryptableAvailableBalance", "docs": ["The decryptable available balance."], "type": { "kind": "definedTypeLinkNode", "name": "decryptableBalance" } }, { "kind": "structFieldTypeNode", "name": "allowConfidentialCredits", "docs": [ "If `false`, the extended account rejects any incoming confidential transfers." ], "type": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "allowNonConfidentialCredits", "docs": ["If `false`, the base account rejects any incoming transfers."], "type": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "pendingBalanceCreditCounter", "docs": [ "The total number of `Deposit` and `Transfer` instructions that have credited `pending_balance`." ], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "maximumPendingBalanceCreditCounter", "docs": [ "The maximum number of `Deposit` and `Transfer` instructions that can", "credit `pending_balance` before the `ApplyPendingBalance`", "instruction is executed." ], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "expectedPendingBalanceCreditCounter", "docs": [ "The `expected_pending_balance_credit_counter` value that was included in", "the last `ApplyPendingBalance` instruction." ], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "actualPendingBalanceCreditCounter", "docs": [ "The actual `pending_balance_credit_counter` when the last", "`ApplyPendingBalance` instruction was executed." ], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } } ] }, "prefix": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } } }, { "kind": "enumStructVariantTypeNode", "name": "defaultAccountState", "struct": { "kind": "sizePrefixTypeNode", "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "state", "docs": [], "type": { "kind": "definedTypeLinkNode", "name": "accountState" } } ] }, "prefix": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } } }, { "kind": "enumStructVariantTypeNode", "name": "immutableOwner", "struct": { "kind": "sizePrefixTypeNode", "type": { "kind": "structTypeNode", "fields": [] }, "prefix": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } } }, { "kind": "enumStructVariantTypeNode", "name": "memoTransfer", "struct": { "kind": "sizePrefixTypeNode", "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "requireIncomingTransferMemos", "docs": [ "Require transfers into this account to be accompanied by a memo." ], "type": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } } ] }, "prefix": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } } }, { "kind": "enumStructVariantTypeNode", "name": "nonTransferable", "struct": { "kind": "sizePrefixTypeNode", "type": { "kind": "structTypeNode", "fields": [] }, "prefix": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } } }, { "kind": "enumStructVariantTypeNode", "name": "interestBearingConfig", "struct": { "kind": "sizePrefixTypeNode", "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "rateAuthority", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "initializationTimestamp", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "preUpdateAverageRate", "docs": [], "type": { "kind": "numberTypeNode", "format": "i16", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "lastUpdateTimestamp", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "currentRate", "docs": [], "type": { "kind": "numberTypeNode", "format": "i16", "endian": "le" } } ] }, "prefix": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } } }, { "kind": "enumStructVariantTypeNode", "name": "cpiGuard", "struct": { "kind": "sizePrefixTypeNode", "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "lockCpi", "docs": [ "Lock certain token operations from taking place within CPI for this account." ], "type": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } } ] }, "prefix": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } } }, { "kind": "enumStructVariantTypeNode", "name": "permanentDelegate", "struct": { "kind": "sizePrefixTypeNode", "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "delegate", "docs": [], "type": { "kind": "publicKeyTypeNode" } } ] }, "prefix": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } } }, { "kind": "enumStructVariantTypeNode", "name": "nonTransferableAccount", "struct": { "kind": "sizePrefixTypeNode", "type": { "kind": "structTypeNode", "fields": [] }, "prefix": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } } }, { "kind": "enumStructVariantTypeNode", "name": "transferHook", "struct": { "kind": "sizePrefixTypeNode", "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "authority", "docs": ["The transfer hook update authority."], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "programId", "docs": ["The transfer hook program account."], "type": { "kind": "publicKeyTypeNode" } } ] }, "prefix": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } } }, { "kind": "enumStructVariantTypeNode", "name": "transferHookAccount", "struct": { "kind": "sizePrefixTypeNode", "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "transferring", "docs": [ "Whether or not this account is currently transferring tokens", "True during the transfer hook cpi, otherwise false." ], "type": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } } ] }, "prefix": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } } }, { "kind": "enumStructVariantTypeNode", "name": "confidentialTransferFee", "struct": { "kind": "sizePrefixTypeNode", "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "authority", "docs": [ "Optional authority to set the withdraw withheld authority ElGamal key." ], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } }, { "kind": "structFieldTypeNode", "name": "elgamalPubkey", "docs": [ "Withheld fees from accounts must be encrypted with this ElGamal key.", "", "Note that whoever holds the ElGamal private key for this ElGamal public", "key has the ability to decode any withheld fee amount that are", "associated with accounts. When combined with the fee parameters, the", "withheld fee amounts can reveal information about transfer amounts." ], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "harvestToMintEnabled", "docs": ["If `false`, the harvest of withheld tokens to mint is rejected."], "type": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "withheldAmount", "docs": [ "Withheld confidential transfer fee tokens that have been moved to the", "mint for withdrawal." ], "type": { "kind": "definedTypeLinkNode", "name": "encryptedBalance" } } ] }, "prefix": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } } }, { "kind": "enumStructVariantTypeNode", "name": "confidentialTransferFeeAmount", "struct": { "kind": "sizePrefixTypeNode", "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "withheldAmount", "docs": [ "Amount withheld during confidential transfers, to be harvest to the mint." ], "type": { "kind": "definedTypeLinkNode", "name": "encryptedBalance" } } ] }, "prefix": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } } }, { "kind": "enumStructVariantTypeNode", "name": "metadataPointer", "struct": { "kind": "sizePrefixTypeNode", "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "authority", "docs": ["Optional authority that can set the metadata address."], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } }, { "kind": "structFieldTypeNode", "name": "metadataAddress", "docs": ["Optional Account Address that holds the metadata."], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } } ] }, "prefix": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } } }, { "kind": "enumStructVariantTypeNode", "name": "tokenMetadata", "struct": { "kind": "sizePrefixTypeNode", "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "updateAuthority", "docs": ["The authority that can sign to update the metadata."], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } }, { "kind": "structFieldTypeNode", "name": "mint", "docs": [ "The associated mint, used to counter spoofing to be sure that metadata belongs to a particular mint." ], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "name", "docs": ["The longer name of the token."], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "symbol", "docs": ["The shortened symbol for the token."], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "uri", "docs": ["The URI pointing to richer metadata."], "type": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } }, { "kind": "structFieldTypeNode", "name": "additionalMetadata", "docs": ["Any additional metadata about the token as key-value pairs."], "type": { "kind": "mapTypeNode", "key": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } }, "value": { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } }, "count": { "kind": "prefixedCountNode", "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } } } ] }, "prefix": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } } }, { "kind": "enumStructVariantTypeNode", "name": "groupPointer", "struct": { "kind": "sizePrefixTypeNode", "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "authority", "docs": ["Optional authority that can set the group address."], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } }, { "kind": "structFieldTypeNode", "name": "groupAddress", "docs": ["Optional account address that holds the group."], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } } ] }, "prefix": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } } }, { "kind": "enumStructVariantTypeNode", "name": "tokenGroup", "struct": { "kind": "sizePrefixTypeNode", "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "updateAuthority", "docs": ["The authority that can sign to update the group."], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } }, { "kind": "structFieldTypeNode", "name": "mint", "docs": [ "The associated mint, used to counter spoofing to be sure that group belongs to a particular mint." ], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "size", "docs": ["The current number of group members."], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "maxSize", "docs": ["The maximum number of group members."], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } } ] }, "prefix": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } } }, { "kind": "enumStructVariantTypeNode", "name": "groupMemberPointer", "struct": { "kind": "sizePrefixTypeNode", "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "authority", "docs": ["Optional authority that can set the member address."], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } }, { "kind": "structFieldTypeNode", "name": "memberAddress", "docs": ["Optional account address that holds the member."], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } } ] }, "prefix": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } } }, { "kind": "enumStructVariantTypeNode", "name": "tokenGroupMember", "struct": { "kind": "sizePrefixTypeNode", "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "mint", "docs": [ "The associated mint, used to counter spoofing to be sure that member belongs to a particular mint." ], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "group", "docs": ["The pubkey of the `TokenGroup`."], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "memberNumber", "docs": ["The member number."], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } } ] }, "prefix": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } } }, { "kind": "enumStructVariantTypeNode", "name": "confidentialMintBurn", "struct": { "kind": "sizePrefixTypeNode", "type": { "kind": "structTypeNode", "fields": [] }, "prefix": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } } }, { "kind": "enumStructVariantTypeNode", "name": "scaledUiAmountConfig", "struct": { "kind": "sizePrefixTypeNode", "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "authority", "docs": [], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "structFieldTypeNode", "name": "multiplier", "docs": [], "type": { "kind": "numberTypeNode", "format": "f64", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "newMultiplierEffectiveTimestamp", "docs": [], "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" } }, { "kind": "structFieldTypeNode", "name": "newMultiplier", "docs": [], "type": { "kind": "numberTypeNode", "format": "f64", "endian": "le" } } ] }, "prefix": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } } }, { "kind": "enumStructVariantTypeNode", "name": "pausableConfig", "struct": { "kind": "sizePrefixTypeNode", "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "authority", "docs": [], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } }, { "kind": "structFieldTypeNode", "name": "paused", "docs": [], "type": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } } ] }, "prefix": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } } }, { "kind": "enumStructVariantTypeNode", "name": "pausableAccount", "struct": { "kind": "sizePrefixTypeNode", "type": { "kind": "structTypeNode", "fields": [] }, "prefix": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } } }, { "kind": "enumStructVariantTypeNode", "name": "permissionedBurn", "struct": { "kind": "sizePrefixTypeNode", "type": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "authority", "docs": ["Authority that is required for burning"], "type": { "kind": "zeroableOptionTypeNode", "item": { "kind": "publicKeyTypeNode" } } } ] }, "prefix": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } } } ], "size": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "extensionType", "docs": [ "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." ], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumEmptyVariantTypeNode", "name": "uninitialized", "docs": ["Used as padding if the account size would otherwise be 355, same as a multisig"] }, { "kind": "enumEmptyVariantTypeNode", "name": "transferFeeConfig", "docs": [ "Includes transfer fee rate info and accompanying authorities to withdraw", "and set the fee" ] }, { "kind": "enumEmptyVariantTypeNode", "name": "transferFeeAmount", "docs": ["Includes withheld transfer fees"] }, { "kind": "enumEmptyVariantTypeNode", "name": "mintCloseAuthority", "docs": ["Includes an optional mint close authority"] }, { "kind": "enumEmptyVariantTypeNode", "name": "confidentialTransferMint", "docs": ["Auditor configuration for confidential transfers"] }, { "kind": "enumEmptyVariantTypeNode", "name": "confidentialTransferAccount", "docs": ["State for confidential transfers"] }, { "kind": "enumEmptyVariantTypeNode", "name": "defaultAccountState", "docs": ["Specifies the default Account::state for new Accounts"] }, { "kind": "enumEmptyVariantTypeNode", "name": "immutableOwner", "docs": ["Indicates that the Account owner authority cannot be changed"] }, { "kind": "enumEmptyVariantTypeNode", "name": "memoTransfer", "docs": ["Require inbound transfers to have memo"] }, { "kind": "enumEmptyVariantTypeNode", "name": "nonTransferable", "docs": ["Indicates that the tokens from this mint can't be transferred"] }, { "kind": "enumEmptyVariantTypeNode", "name": "interestBearingConfig", "docs": ["Tokens accrue interest over time,"] }, { "kind": "enumEmptyVariantTypeNode", "name": "cpiGuard", "docs": ["Locks privileged token operations from happening via CPI"] }, { "kind": "enumEmptyVariantTypeNode", "name": "permanentDelegate", "docs": ["Includes an optional permanent delegate"] }, { "kind": "enumEmptyVariantTypeNode", "name": "nonTransferableAccount", "docs": ["Indicates that the tokens in this account belong to a non-transferable", "mint"] }, { "kind": "enumEmptyVariantTypeNode", "name": "transferHook", "docs": ["Mint requires a CPI to a program implementing the \"transfer hook\"", "interface"] }, { "kind": "enumEmptyVariantTypeNode", "name": "transferHookAccount", "docs": [ "Indicates that the tokens in this account belong to a mint with a", "transfer hook" ] }, { "kind": "enumEmptyVariantTypeNode", "name": "confidentialTransferFee", "docs": [ "Includes encrypted withheld fees and the encryption public that they are", "encrypted under" ] }, { "kind": "enumEmptyVariantTypeNode", "name": "confidentialTransferFeeAmount", "docs": ["Includes confidential withheld transfer fees"] }, { "kind": "enumEmptyVariantTypeNode", "name": "scaledUiAmountConfig", "docs": ["Tokens have a scaled UI amount"] }, { "kind": "enumEmptyVariantTypeNode", "name": "pausableConfig", "docs": ["Mint contains pausable configuration"] }, { "kind": "enumEmptyVariantTypeNode", "name": "pausableAccount", "docs": ["Account contains pausable configuration"] }, { "kind": "enumEmptyVariantTypeNode", "name": "metadataPointer", "docs": [ "Mint contains a pointer to another account (or the same account) that", "holds metadata" ] }, { "kind": "enumEmptyVariantTypeNode", "name": "tokenMetadata", "docs": ["Mint contains token-metadata"] }, { "kind": "enumEmptyVariantTypeNode", "name": "groupPointer", "docs": [ "Mint contains a pointer to another account (or the same account) that", "holds group configurations" ] }, { "kind": "enumEmptyVariantTypeNode", "name": "tokenGroup", "docs": ["Mint contains token group configurations"] }, { "kind": "enumEmptyVariantTypeNode", "name": "groupMemberPointer", "docs": [ "Mint contains a pointer to another account (or the same account) that", "holds group member configurations" ] }, { "kind": "enumEmptyVariantTypeNode", "name": "tokenGroupMember", "docs": ["Mint contains token group member configurations"] } ], "size": { "kind": "numberTypeNode", "format": "u16", "endian": "le" } } }, { "kind": "definedTypeNode", "name": "tokenMetadataField", "docs": ["Fields in the metadata account, used for updating."], "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumEmptyVariantTypeNode", "name": "name", "docs": ["The name field, corresponding to `TokenMetadata.name`"] }, { "kind": "enumEmptyVariantTypeNode", "name": "symbol", "docs": ["The symbol field, corresponding to `TokenMetadata.symbol`"] }, { "kind": "enumEmptyVariantTypeNode", "name": "uri", "docs": ["The uri field, corresponding to `TokenMetadata.uri`"] }, { "kind": "enumTupleVariantTypeNode", "name": "key", "docs": ["A user field, whose key is given by the associated string"], "tuple": { "kind": "tupleTypeNode", "items": [ { "kind": "sizePrefixTypeNode", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" } } ] } } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } } } ], "pdas": [], "errors": [ { "kind": "errorNode", "name": "notRentExempt", "code": 0, "message": "Lamport balance below rent-exempt threshold", "docs": ["NotRentExempt: Lamport balance below rent-exempt threshold"] }, { "kind": "errorNode", "name": "insufficientFunds", "code": 1, "message": "Insufficient funds", "docs": ["InsufficientFunds: Insufficient funds"] }, { "kind": "errorNode", "name": "invalidMint", "code": 2, "message": "Invalid Mint", "docs": ["InvalidMint: Invalid Mint"] }, { "kind": "errorNode", "name": "mintMismatch", "code": 3, "message": "Account not associated with this Mint", "docs": ["MintMismatch: Account not associated with this Mint"] }, { "kind": "errorNode", "name": "ownerMismatch", "code": 4, "message": "Owner does not match", "docs": ["OwnerMismatch: Owner does not match"] }, { "kind": "errorNode", "name": "fixedSupply", "code": 5, "message": "Fixed supply", "docs": ["FixedSupply: Fixed supply"] }, { "kind": "errorNode", "name": "alreadyInUse", "code": 6, "message": "Already in use", "docs": ["AlreadyInUse: Already in use"] }, { "kind": "errorNode", "name": "invalidNumberOfProvidedSigners", "code": 7, "message": "Invalid number of provided signers", "docs": ["InvalidNumberOfProvidedSigners: Invalid number of provided signers"] }, { "kind": "errorNode", "name": "invalidNumberOfRequiredSigners", "code": 8, "message": "Invalid number of required signers", "docs": ["InvalidNumberOfRequiredSigners: Invalid number of required signers"] }, { "kind": "errorNode", "name": "uninitializedState", "code": 9, "message": "State is unititialized", "docs": ["UninitializedState: State is unititialized"] }, { "kind": "errorNode", "name": "nativeNotSupported", "code": 10, "message": "Instruction does not support native tokens", "docs": ["NativeNotSupported: Instruction does not support native tokens"] }, { "kind": "errorNode", "name": "nonNativeHasBalance", "code": 11, "message": "Non-native account can only be closed if its balance is zero", "docs": ["NonNativeHasBalance: Non-native account can only be closed if its balance is zero"] }, { "kind": "errorNode", "name": "invalidInstruction", "code": 12, "message": "Invalid instruction", "docs": ["InvalidInstruction: Invalid instruction"] }, { "kind": "errorNode", "name": "invalidState", "code": 13, "message": "State is invalid for requested operation", "docs": ["InvalidState: State is invalid for requested operation"] }, { "kind": "errorNode", "name": "overflow", "code": 14, "message": "Operation overflowed", "docs": ["Overflow: Operation overflowed"] }, { "kind": "errorNode", "name": "authorityTypeNotSupported", "code": 15, "message": "Account does not support specified authority type", "docs": ["AuthorityTypeNotSupported: Account does not support specified authority type"] }, { "kind": "errorNode", "name": "mintCannotFreeze", "code": 16, "message": "This token mint cannot freeze accounts", "docs": ["MintCannotFreeze: This token mint cannot freeze accounts"] }, { "kind": "errorNode", "name": "accountFrozen", "code": 17, "message": "Account is frozen", "docs": ["AccountFrozen: Account is frozen"] }, { "kind": "errorNode", "name": "mintDecimalsMismatch", "code": 18, "message": "The provided decimals value different from the Mint decimals", "docs": ["MintDecimalsMismatch: The provided decimals value different from the Mint decimals"] }, { "kind": "errorNode", "name": "nonNativeNotSupported", "code": 19, "message": "Instruction does not support non-native tokens", "docs": ["NonNativeNotSupported: Instruction does not support non-native tokens"] } ] }, "additionalPrograms": [ { "kind": "programNode", "name": "associatedToken", "publicKey": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", "version": "1.1.1", "origin": "shank", "docs": [], "accounts": [], "instructions": [ { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Funding account (must be a system account)."], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "ata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Associated token account address to be created."], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "accountValueNode", "name": "owner" } }, { "kind": "pdaSeedValueNode", "name": "tokenProgram", "value": { "kind": "accountValueNode", "name": "tokenProgram" } }, { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "owner", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Wallet address for the new associated token account."] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The token mint for the new associated token account."] }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program."], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "tokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["SPL Token program."], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 0 }, "defaultValueStrategy": "omitted" } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "name": "createAssociatedToken", "docs": [ "Creates an associated token account for the given wallet address and", "token mint Returns an error if the account exists." ], "optionalAccountStrategy": "programId" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Funding account (must be a system account)."], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "ata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Associated token account address to be created."], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "accountValueNode", "name": "owner" } }, { "kind": "pdaSeedValueNode", "name": "tokenProgram", "value": { "kind": "accountValueNode", "name": "tokenProgram" } }, { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "owner", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Wallet address for the new associated token account."] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The token mint for the new associated token account."] }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program."], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "tokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["SPL Token program."], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 1 }, "defaultValueStrategy": "omitted" } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "name": "createAssociatedTokenIdempotent", "docs": [ "Creates an associated token account for the given wallet address and", "token mint, if it doesn't already exist. Returns an error if the", "account exists, but with a different owner." ], "optionalAccountStrategy": "programId" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "nestedAssociatedAccountAddress", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [ "Nested associated token account, must be owned by `ownerAssociatedAccountAddress`." ], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "accountValueNode", "name": "ownerAssociatedAccountAddress" } }, { "kind": "pdaSeedValueNode", "name": "tokenProgram", "value": { "kind": "accountValueNode", "name": "tokenProgram" } }, { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "nestedTokenMintAddress" } } ] } }, { "kind": "instructionAccountNode", "name": "nestedTokenMintAddress", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Token mint for the nested associated token account."] }, { "kind": "instructionAccountNode", "name": "destinationAssociatedAccountAddress", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Wallet's associated token account."], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "accountValueNode", "name": "walletAddress" } }, { "kind": "pdaSeedValueNode", "name": "tokenProgram", "value": { "kind": "accountValueNode", "name": "tokenProgram" } }, { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "nestedTokenMintAddress" } } ] } }, { "kind": "instructionAccountNode", "name": "ownerAssociatedAccountAddress", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Owner associated token account address, must be owned by `walletAddress`."], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "accountValueNode", "name": "walletAddress" } }, { "kind": "pdaSeedValueNode", "name": "tokenProgram", "value": { "kind": "accountValueNode", "name": "tokenProgram" } }, { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "ownerTokenMintAddress" } } ] } }, { "kind": "instructionAccountNode", "name": "ownerTokenMintAddress", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Token mint for the owner associated token account."] }, { "kind": "instructionAccountNode", "name": "walletAddress", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Wallet address for the owner associated token account."] }, { "kind": "instructionAccountNode", "name": "tokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["SPL Token program."], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 2 }, "defaultValueStrategy": "omitted" } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "name": "recoverNestedAssociatedToken", "docs": [ "Transfers from and closes a nested associated token account: an", "associated token account owned by an associated token account.", "", "The tokens are moved from the nested associated token account to the", "wallet's associated token account, and the nested account lamports are", "moved to the wallet.", "", "Note: Nested token accounts are an anti-pattern, and almost always", "created unintentionally, so this instruction should only be used to", "recover from errors." ], "optionalAccountStrategy": "programId" } ], "definedTypes": [], "pdas": [ { "kind": "pdaNode", "name": "associatedToken", "docs": [], "seeds": [ { "kind": "variablePdaSeedNode", "name": "owner", "docs": ["The wallet address of the associated token account."], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "variablePdaSeedNode", "name": "tokenProgram", "docs": ["The address of the token program to use."], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "variablePdaSeedNode", "name": "mint", "docs": ["The mint address of the associated token account."], "type": { "kind": "publicKeyTypeNode" } } ] } ], "errors": [ { "kind": "errorNode", "name": "invalidOwner", "code": 0, "message": "Associated token account owner does not match address derivation", "docs": ["InvalidOwner: Associated token account owner does not match address derivation"] } ] } ] } ================================================ FILE: packages/dynamic-client/test/programs/idls/token-idl.json ================================================ { "kind": "rootNode", "program": { "kind": "programNode", "pdas": [], "accounts": [ { "kind": "accountNode", "data": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "mintAuthority", "type": { "kind": "optionTypeNode", "item": { "kind": "publicKeyTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" }, "fixed": true }, "docs": [ "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." ] }, { "kind": "structFieldTypeNode", "name": "supply", "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "docs": ["Total supply of tokens."] }, { "kind": "structFieldTypeNode", "name": "decimals", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": ["Number of base 10 digits to the right of the decimal place."] }, { "kind": "structFieldTypeNode", "name": "isInitialized", "type": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "docs": ["Is `true` if this structure has been initialized."] }, { "kind": "structFieldTypeNode", "name": "freezeAuthority", "type": { "kind": "optionTypeNode", "item": { "kind": "publicKeyTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" }, "fixed": true }, "docs": ["Optional authority to freeze token accounts."] } ] }, "discriminators": [ { "kind": "sizeDiscriminatorNode", "size": 82 } ], "name": "mint", "docs": [], "size": 82 }, { "kind": "accountNode", "data": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "mint", "type": { "kind": "publicKeyTypeNode" }, "docs": ["The mint associated with this account."] }, { "kind": "structFieldTypeNode", "name": "owner", "type": { "kind": "publicKeyTypeNode" }, "docs": ["The owner of this account."] }, { "kind": "structFieldTypeNode", "name": "amount", "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "docs": ["The amount of tokens this account holds."] }, { "kind": "structFieldTypeNode", "name": "delegate", "type": { "kind": "optionTypeNode", "item": { "kind": "publicKeyTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" }, "fixed": true }, "docs": [ "If `delegate` is `Some` then `delegated_amount` represents", "the amount authorized by the delegate." ] }, { "kind": "structFieldTypeNode", "name": "state", "type": { "kind": "definedTypeLinkNode", "name": "accountState" }, "docs": ["The account's state."] }, { "kind": "structFieldTypeNode", "name": "isNative", "type": { "kind": "optionTypeNode", "item": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" }, "fixed": true }, "docs": [ "If is_native.is_some, this is a native token, and the value logs the", "rent-exempt reserve. An Account is required to be rent-exempt, so", "the value is used by the Processor to ensure that wrapped SOL", "accounts do not drop below this threshold." ] }, { "kind": "structFieldTypeNode", "name": "delegatedAmount", "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "docs": ["The amount delegated."] }, { "kind": "structFieldTypeNode", "name": "closeAuthority", "type": { "kind": "optionTypeNode", "item": { "kind": "publicKeyTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u32", "endian": "le" }, "fixed": true }, "docs": ["Optional authority to close the account."] } ] }, "discriminators": [ { "kind": "sizeDiscriminatorNode", "size": 165 } ], "name": "token", "docs": [], "size": 165 }, { "kind": "accountNode", "data": { "kind": "structTypeNode", "fields": [ { "kind": "structFieldTypeNode", "name": "m", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": ["Number of signers required."] }, { "kind": "structFieldTypeNode", "name": "n", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": ["Number of valid signers."] }, { "kind": "structFieldTypeNode", "name": "isInitialized", "type": { "kind": "booleanTypeNode", "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "docs": ["Is `true` if this structure has been initialized."] }, { "kind": "structFieldTypeNode", "name": "signers", "type": { "kind": "arrayTypeNode", "item": { "kind": "publicKeyTypeNode" }, "count": { "kind": "fixedCountNode", "value": 11 } }, "docs": ["Signer public keys."] } ] }, "discriminators": [ { "kind": "sizeDiscriminatorNode", "size": 355 } ], "name": "multisig", "docs": [], "size": 355 } ], "instructions": [ { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Token mint account."] }, { "kind": "instructionAccountNode", "name": "rent", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Rent sysvar."], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "SysvarRent111111111111111111111111111111111" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 0 }, "defaultValueStrategy": "omitted" }, { "kind": "instructionArgumentNode", "name": "decimals", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": ["Number of decimals in token account amounts."] }, { "kind": "instructionArgumentNode", "name": "mintAuthority", "type": { "kind": "publicKeyTypeNode" }, "docs": ["Minting authority."] }, { "kind": "instructionArgumentNode", "name": "freezeAuthority", "type": { "kind": "optionTypeNode", "item": { "kind": "publicKeyTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "fixed": false }, "defaultValue": { "kind": "noneValueNode" }, "docs": ["Optional authority that can freeze token accounts."] } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "name": "initializeMint", "docs": [ "Initializes a new mint and optionally deposits all the newly minted", "tokens in an account.", "", "The `InitializeMint` instruction requires no signers and MUST be", "included within the same Transaction as the system program's", "`CreateAccount` instruction that creates the account being initialized.", "Otherwise another party can acquire ownership of the uninitialized account." ], "optionalAccountStrategy": "programId" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "account", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The account to initialize."] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The mint this account will be associated with."] }, { "kind": "instructionAccountNode", "name": "owner", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The new account's owner/multisignature."] }, { "kind": "instructionAccountNode", "name": "rent", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Rent sysvar."], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "SysvarRent111111111111111111111111111111111" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 1 }, "defaultValueStrategy": "omitted" } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "name": "initializeAccount", "docs": [ "Initializes a new account to hold tokens. If this account is associated", "with the native mint then the token balance of the initialized account", "will be equal to the amount of SOL in the account. If this account is", "associated with another mint, that mint must be initialized before this", "command can succeed.", "", "The `InitializeAccount` instruction requires no signers and MUST be", "included within the same Transaction as the system program's", "`CreateAccount` instruction that creates the account being initialized.", "Otherwise another party can acquire ownership of the uninitialized account." ], "optionalAccountStrategy": "programId" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "multisig", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The multisignature account to initialize."] }, { "kind": "instructionAccountNode", "name": "rent", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Rent sysvar."], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "SysvarRent111111111111111111111111111111111" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 2 }, "defaultValueStrategy": "omitted" }, { "kind": "instructionArgumentNode", "name": "m", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": ["The number of signers (M) required to validate this multisignature account."] } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "value": { "kind": "argumentValueNode", "name": "signers" } } ], "name": "initializeMultisig", "docs": [ "Initializes a multisignature account with N provided signers.", "", "Multisignature accounts can used in place of any single owner/delegate", "accounts in any token instruction that require an owner/delegate to be", "present. The variant field represents the number of signers (M)", "required to validate this multisignature account.", "", "The `InitializeMultisig` instruction requires no signers and MUST be", "included within the same Transaction as the system program's", "`CreateAccount` instruction that creates the account being initialized.", "Otherwise another party can acquire ownership of the uninitialized account." ], "optionalAccountStrategy": "programId" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "source", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The source account."] }, { "kind": "instructionAccountNode", "name": "destination", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The destination account."] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The source account's owner/delegate or its multisignature account."], "defaultValue": { "kind": "identityValueNode" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 3 }, "defaultValueStrategy": "omitted" }, { "kind": "instructionArgumentNode", "name": "amount", "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "docs": ["The amount of tokens to transfer."] } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "value": { "kind": "argumentValueNode", "name": "multiSigners" }, "isOptional": true, "isSigner": true } ], "name": "transfer", "docs": [ "Transfers tokens from one account to another either directly or via a delegate.", "If this account is associated with the native mint then equal amounts", "of SOL and Tokens will be transferred to the destination account." ], "optionalAccountStrategy": "programId" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "source", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The source account."] }, { "kind": "instructionAccountNode", "name": "delegate", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The delegate."] }, { "kind": "instructionAccountNode", "name": "owner", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The source account owner or its multisignature account."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 4 }, "defaultValueStrategy": "omitted" }, { "kind": "instructionArgumentNode", "name": "amount", "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "docs": ["The amount of tokens the delegate is approved for."] } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "value": { "kind": "argumentValueNode", "name": "multiSigners" }, "isOptional": true, "isSigner": true } ], "name": "approve", "docs": [ "Approves a delegate. A delegate is given the authority over tokens on", "behalf of the source account's owner." ], "optionalAccountStrategy": "programId" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "source", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The source account."] }, { "kind": "instructionAccountNode", "name": "owner", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The source account owner or its multisignature."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 5 }, "defaultValueStrategy": "omitted" } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "value": { "kind": "argumentValueNode", "name": "multiSigners" }, "isOptional": true, "isSigner": true } ], "name": "revoke", "docs": ["Revokes the delegate's authority."], "optionalAccountStrategy": "programId" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "owned", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The mint or account to change the authority of."] }, { "kind": "instructionAccountNode", "name": "owner", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": [ "The current authority or the multisignature account of the mint or account to update." ] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 6 }, "defaultValueStrategy": "omitted" }, { "kind": "instructionArgumentNode", "name": "authorityType", "type": { "kind": "definedTypeLinkNode", "name": "authorityType" }, "docs": ["The type of authority to update."] }, { "kind": "instructionArgumentNode", "name": "newAuthority", "type": { "kind": "optionTypeNode", "item": { "kind": "publicKeyTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "fixed": false }, "docs": ["The new authority"] } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "value": { "kind": "argumentValueNode", "name": "multiSigners" }, "isOptional": true, "isSigner": true } ], "name": "setAuthority", "docs": ["Sets a new authority of a mint or account."], "optionalAccountStrategy": "programId" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The mint account."] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The account to mint tokens to."] }, { "kind": "instructionAccountNode", "name": "mintAuthority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The mint's minting authority or its multisignature account."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 7 }, "defaultValueStrategy": "omitted" }, { "kind": "instructionArgumentNode", "name": "amount", "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "docs": ["The amount of new tokens to mint."] } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "value": { "kind": "argumentValueNode", "name": "multiSigners" }, "isOptional": true, "isSigner": true } ], "name": "mintTo", "docs": ["Mints new tokens to an account. The native mint does not support minting."], "optionalAccountStrategy": "programId" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "account", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The account to burn from."] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The token mint."] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The account's owner/delegate or its multisignature account."], "defaultValue": { "kind": "identityValueNode" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": ["The amount of tokens to burn."], "defaultValue": { "kind": "numberValueNode", "number": 8 }, "defaultValueStrategy": "omitted" }, { "kind": "instructionArgumentNode", "name": "amount", "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "docs": [] } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "value": { "kind": "argumentValueNode", "name": "multiSigners" }, "isOptional": true, "isSigner": true } ], "name": "burn", "docs": [ "Burns tokens by removing them from an account. `Burn` does not support", "accounts associated with the native mint, use `CloseAccount` instead." ], "optionalAccountStrategy": "programId" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "account", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The account to close."] }, { "kind": "instructionAccountNode", "name": "destination", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The destination account."] }, { "kind": "instructionAccountNode", "name": "owner", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The account's owner or its multisignature account."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 9 }, "defaultValueStrategy": "omitted" } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "value": { "kind": "argumentValueNode", "name": "multiSigners" }, "isOptional": true, "isSigner": true } ], "name": "closeAccount", "docs": [ "Close an account by transferring all its SOL to the destination account.", "Non-native accounts may only be closed if its token amount is zero." ], "optionalAccountStrategy": "programId" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "account", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The account to freeze."] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The token mint."] }, { "kind": "instructionAccountNode", "name": "owner", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The mint freeze authority or its multisignature account."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 10 }, "defaultValueStrategy": "omitted" } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "value": { "kind": "argumentValueNode", "name": "multiSigners" }, "isOptional": true, "isSigner": true } ], "name": "freezeAccount", "docs": ["Freeze an Initialized account using the Mint's freeze_authority (if set)."], "optionalAccountStrategy": "programId" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "account", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The account to thaw."] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The token mint."] }, { "kind": "instructionAccountNode", "name": "owner", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The mint freeze authority or its multisignature account."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 11 }, "defaultValueStrategy": "omitted" } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "value": { "kind": "argumentValueNode", "name": "multiSigners" }, "isOptional": true, "isSigner": true } ], "name": "thawAccount", "docs": ["Thaw a Frozen account using the Mint's freeze_authority (if set)."], "optionalAccountStrategy": "programId" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "source", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The source account."] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The token mint."] }, { "kind": "instructionAccountNode", "name": "destination", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The destination account."] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The source account's owner/delegate or its multisignature account."], "defaultValue": { "kind": "identityValueNode" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 12 }, "defaultValueStrategy": "omitted" }, { "kind": "instructionArgumentNode", "name": "amount", "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "docs": ["The amount of tokens to transfer."] }, { "kind": "instructionArgumentNode", "name": "decimals", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": ["Expected number of base 10 digits to the right of the decimal place."] } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "value": { "kind": "argumentValueNode", "name": "multiSigners" }, "isOptional": true, "isSigner": true } ], "name": "transferChecked", "docs": [ "Transfers tokens from one account to another either directly or via a", "delegate. If this account is associated with the native mint then equal", "amounts of SOL and Tokens will be transferred to the destination account.", "", "This instruction differs from Transfer in that the token mint and", "decimals value is checked by the caller. This may be useful when", "creating transactions offline or within a hardware wallet." ], "optionalAccountStrategy": "programId" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "source", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The source account."] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The token mint."] }, { "kind": "instructionAccountNode", "name": "delegate", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The delegate."] }, { "kind": "instructionAccountNode", "name": "owner", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The source account owner or its multisignature account."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 13 }, "defaultValueStrategy": "omitted" }, { "kind": "instructionArgumentNode", "name": "amount", "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "docs": ["The amount of tokens the delegate is approved for."] }, { "kind": "instructionArgumentNode", "name": "decimals", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": ["Expected number of base 10 digits to the right of the decimal place."] } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "value": { "kind": "argumentValueNode", "name": "multiSigners" }, "isOptional": true, "isSigner": true } ], "name": "approveChecked", "docs": [ "Approves a delegate. A delegate is given the authority over tokens on", "behalf of the source account's owner.", "", "This instruction differs from Approve in that the token mint and", "decimals value is checked by the caller. This may be useful when", "creating transactions offline or within a hardware wallet." ], "optionalAccountStrategy": "programId" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The mint."] }, { "kind": "instructionAccountNode", "name": "token", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The account to mint tokens to."] }, { "kind": "instructionAccountNode", "name": "mintAuthority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The mint's minting authority or its multisignature account."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 14 }, "defaultValueStrategy": "omitted" }, { "kind": "instructionArgumentNode", "name": "amount", "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "docs": ["The amount of new tokens to mint."] }, { "kind": "instructionArgumentNode", "name": "decimals", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": ["Expected number of base 10 digits to the right of the decimal place."] } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "value": { "kind": "argumentValueNode", "name": "multiSigners" }, "isOptional": true, "isSigner": true } ], "name": "mintToChecked", "docs": [ "Mints new tokens to an account. The native mint does not support minting.", "", "This instruction differs from MintTo in that the decimals value is", "checked by the caller. This may be useful when creating transactions", "offline or within a hardware wallet." ], "optionalAccountStrategy": "programId" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "account", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The account to burn from."] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The token mint."] }, { "kind": "instructionAccountNode", "name": "authority", "isWritable": false, "isSigner": "either", "isOptional": false, "docs": ["The account's owner/delegate or its multisignature account."], "defaultValue": { "kind": "identityValueNode" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 15 }, "defaultValueStrategy": "omitted" }, { "kind": "instructionArgumentNode", "name": "amount", "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "docs": ["The amount of tokens to burn."] }, { "kind": "instructionArgumentNode", "name": "decimals", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": ["Expected number of base 10 digits to the right of the decimal place."] } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "value": { "kind": "argumentValueNode", "name": "multiSigners" }, "isOptional": true, "isSigner": true } ], "name": "burnChecked", "docs": [ "Burns tokens by removing them from an account. `BurnChecked` does not", "support accounts associated with the native mint, use `CloseAccount` instead.", "", "This instruction differs from Burn in that the decimals value is checked", "by the caller. This may be useful when creating transactions offline or", "within a hardware wallet." ], "optionalAccountStrategy": "programId" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "account", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The account to initialize."] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The mint this account will be associated with."] }, { "kind": "instructionAccountNode", "name": "rent", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Rent sysvar."], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "SysvarRent111111111111111111111111111111111" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 16 }, "defaultValueStrategy": "omitted" }, { "kind": "instructionArgumentNode", "name": "owner", "type": { "kind": "publicKeyTypeNode" }, "docs": ["The new account's owner/multisignature."] } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "name": "initializeAccount2", "docs": [ "Like InitializeAccount, but the owner pubkey is passed via instruction", "data rather than the accounts list. This variant may be preferable", "when using Cross Program Invocation from an instruction that does", "not need the owner's `AccountInfo` otherwise." ], "optionalAccountStrategy": "programId" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "account", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The native token account to sync with its underlying lamports."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 17 }, "defaultValueStrategy": "omitted" } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "name": "syncNative", "docs": [ "Given a wrapped / native token account (a token account containing SOL)", "updates its amount field based on the account's underlying `lamports`.", "This is useful if a non-wrapped SOL account uses", "`system_instruction::transfer` to move lamports to a wrapped token", "account, and needs to have its token `amount` field updated." ], "optionalAccountStrategy": "programId" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "account", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The account to initialize."] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The mint this account will be associated with."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 18 }, "defaultValueStrategy": "omitted" }, { "kind": "instructionArgumentNode", "name": "owner", "type": { "kind": "publicKeyTypeNode" }, "docs": ["The new account's owner/multisignature."] } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "name": "initializeAccount3", "docs": ["Like InitializeAccount2, but does not require the Rent sysvar to be provided."], "optionalAccountStrategy": "programId" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "multisig", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The multisignature account to initialize."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 19 }, "defaultValueStrategy": "omitted" }, { "kind": "instructionArgumentNode", "name": "m", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": ["The number of signers (M) required to validate this multisignature account."] } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "remainingAccounts": [ { "kind": "instructionRemainingAccountsNode", "value": { "kind": "argumentValueNode", "name": "signers" } } ], "name": "initializeMultisig2", "docs": ["Like InitializeMultisig, but does not require the Rent sysvar to be provided."], "optionalAccountStrategy": "programId" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The mint to initialize."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 20 }, "defaultValueStrategy": "omitted" }, { "kind": "instructionArgumentNode", "name": "decimals", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": ["Number of base 10 digits to the right of the decimal place."] }, { "kind": "instructionArgumentNode", "name": "mintAuthority", "type": { "kind": "publicKeyTypeNode" }, "docs": ["The authority/multisignature to mint tokens."] }, { "kind": "instructionArgumentNode", "name": "freezeAuthority", "type": { "kind": "optionTypeNode", "item": { "kind": "publicKeyTypeNode" }, "prefix": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "fixed": false }, "defaultValue": { "kind": "noneValueNode" }, "docs": ["The optional freeze authority/multisignature of the mint."] } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "name": "initializeMint2", "docs": ["Like [`InitializeMint`], but does not require the Rent sysvar to be provided."], "optionalAccountStrategy": "programId" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The mint to calculate for."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 21 }, "defaultValueStrategy": "omitted" } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "name": "getAccountDataSize", "docs": [ "Gets the required size of an account for the given mint as a", "little-endian `u64`.", "", "Return data can be fetched using `sol_get_return_data` and deserializing", "the return data as a little-endian `u64`." ], "optionalAccountStrategy": "programId" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "account", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["The account to initialize."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 22 }, "defaultValueStrategy": "omitted" } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "name": "initializeImmutableOwner", "docs": [ "Initialize the Immutable Owner extension for the given token account", "", "Fails if the account has already been initialized, so must be called", "before `InitializeAccount`.", "", "No-ops in this version of the program, but is included for compatibility", "with the Associated Token Account program." ], "optionalAccountStrategy": "programId" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The mint to calculate for."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 23 }, "defaultValueStrategy": "omitted" }, { "kind": "instructionArgumentNode", "name": "amount", "type": { "kind": "numberTypeNode", "format": "u64", "endian": "le" }, "docs": ["The amount of tokens to reformat."] } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "name": "amountToUiAmount", "docs": [ "Convert an Amount of tokens to a UiAmount `string`, using the given", "mint. In this version of the program, the mint can only specify the", "number of decimals.", "", "Fails on an invalid mint.", "", "Return data can be fetched using `sol_get_return_data` and deserialized", "with `String::from_utf8`." ], "optionalAccountStrategy": "programId" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The mint to calculate for."] } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 24 }, "defaultValueStrategy": "omitted" }, { "kind": "instructionArgumentNode", "name": "uiAmount", "type": { "kind": "stringTypeNode", "encoding": "utf8" }, "docs": ["The ui_amount of tokens to reformat."] } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "name": "uiAmountToAmount", "docs": [ "Convert a UiAmount of tokens to a little-endian `u64` raw Amount, using", "the given mint. In this version of the program, the mint can only", "specify the number of decimals.", "", "Return data can be fetched using `sol_get_return_data` and deserializing", "the return data as a little-endian `u64`." ], "optionalAccountStrategy": "programId" } ], "definedTypes": [ { "kind": "definedTypeNode", "name": "accountState", "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumEmptyVariantTypeNode", "name": "uninitialized" }, { "kind": "enumEmptyVariantTypeNode", "name": "initialized" }, { "kind": "enumEmptyVariantTypeNode", "name": "frozen" } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "docs": [] }, { "kind": "definedTypeNode", "name": "authorityType", "type": { "kind": "enumTypeNode", "variants": [ { "kind": "enumEmptyVariantTypeNode", "name": "mintTokens" }, { "kind": "enumEmptyVariantTypeNode", "name": "freezeAccount" }, { "kind": "enumEmptyVariantTypeNode", "name": "accountOwner" }, { "kind": "enumEmptyVariantTypeNode", "name": "closeAccount" } ], "size": { "kind": "numberTypeNode", "format": "u8", "endian": "le" } }, "docs": [] } ], "errors": [ { "kind": "errorNode", "name": "notRentExempt", "code": 0, "message": "Lamport balance below rent-exempt threshold", "docs": ["NotRentExempt: Lamport balance below rent-exempt threshold"] }, { "kind": "errorNode", "name": "insufficientFunds", "code": 1, "message": "Insufficient funds", "docs": ["InsufficientFunds: Insufficient funds"] }, { "kind": "errorNode", "name": "invalidMint", "code": 2, "message": "Invalid Mint", "docs": ["InvalidMint: Invalid Mint"] }, { "kind": "errorNode", "name": "mintMismatch", "code": 3, "message": "Account not associated with this Mint", "docs": ["MintMismatch: Account not associated with this Mint"] }, { "kind": "errorNode", "name": "ownerMismatch", "code": 4, "message": "Owner does not match", "docs": ["OwnerMismatch: Owner does not match"] }, { "kind": "errorNode", "name": "fixedSupply", "code": 5, "message": "Fixed supply", "docs": ["FixedSupply: Fixed supply"] }, { "kind": "errorNode", "name": "alreadyInUse", "code": 6, "message": "Already in use", "docs": ["AlreadyInUse: Already in use"] }, { "kind": "errorNode", "name": "invalidNumberOfProvidedSigners", "code": 7, "message": "Invalid number of provided signers", "docs": ["InvalidNumberOfProvidedSigners: Invalid number of provided signers"] }, { "kind": "errorNode", "name": "invalidNumberOfRequiredSigners", "code": 8, "message": "Invalid number of required signers", "docs": ["InvalidNumberOfRequiredSigners: Invalid number of required signers"] }, { "kind": "errorNode", "name": "uninitializedState", "code": 9, "message": "State is unititialized", "docs": ["UninitializedState: State is unititialized"] }, { "kind": "errorNode", "name": "nativeNotSupported", "code": 10, "message": "Instruction does not support native tokens", "docs": ["NativeNotSupported: Instruction does not support native tokens"] }, { "kind": "errorNode", "name": "nonNativeHasBalance", "code": 11, "message": "Non-native account can only be closed if its balance is zero", "docs": ["NonNativeHasBalance: Non-native account can only be closed if its balance is zero"] }, { "kind": "errorNode", "name": "invalidInstruction", "code": 12, "message": "Invalid instruction", "docs": ["InvalidInstruction: Invalid instruction"] }, { "kind": "errorNode", "name": "invalidState", "code": 13, "message": "State is invalid for requested operation", "docs": ["InvalidState: State is invalid for requested operation"] }, { "kind": "errorNode", "name": "overflow", "code": 14, "message": "Operation overflowed", "docs": ["Overflow: Operation overflowed"] }, { "kind": "errorNode", "name": "authorityTypeNotSupported", "code": 15, "message": "Account does not support specified authority type", "docs": ["AuthorityTypeNotSupported: Account does not support specified authority type"] }, { "kind": "errorNode", "name": "mintCannotFreeze", "code": 16, "message": "This token mint cannot freeze accounts", "docs": ["MintCannotFreeze: This token mint cannot freeze accounts"] }, { "kind": "errorNode", "name": "accountFrozen", "code": 17, "message": "Account is frozen", "docs": ["AccountFrozen: Account is frozen"] }, { "kind": "errorNode", "name": "mintDecimalsMismatch", "code": 18, "message": "The provided decimals value different from the Mint decimals", "docs": ["MintDecimalsMismatch: The provided decimals value different from the Mint decimals"] }, { "kind": "errorNode", "name": "nonNativeNotSupported", "code": 19, "message": "Instruction does not support non-native tokens", "docs": ["NonNativeNotSupported: Instruction does not support non-native tokens"] } ], "name": "token", "prefix": "", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", "version": "3.3.0", "origin": "shank" }, "additionalPrograms": [ { "kind": "programNode", "pdas": [ { "kind": "pdaNode", "name": "associatedToken", "seeds": [ { "kind": "variablePdaSeedNode", "name": "owner", "docs": ["The wallet address of the associated token account."], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "variablePdaSeedNode", "name": "tokenProgram", "docs": ["The address of the token program to use."], "type": { "kind": "publicKeyTypeNode" } }, { "kind": "variablePdaSeedNode", "name": "mint", "docs": ["The mint address of the associated token account."], "type": { "kind": "publicKeyTypeNode" } } ] } ], "accounts": [], "instructions": [ { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Funding account (must be a system account)."], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "ata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Associated token account address to be created."], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "accountValueNode", "name": "owner" } }, { "kind": "pdaSeedValueNode", "name": "tokenProgram", "value": { "kind": "accountValueNode", "name": "tokenProgram" } }, { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "owner", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Wallet address for the new associated token account."] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The token mint for the new associated token account."] }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program."], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "tokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["SPL Token program."], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 0 }, "defaultValueStrategy": "omitted" } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "name": "createAssociatedToken", "docs": [ "Creates an associated token account for the given wallet address and", "token mint Returns an error if the account exists." ], "optionalAccountStrategy": "programId" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "payer", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Funding account (must be a system account)."], "defaultValue": { "kind": "payerValueNode" } }, { "kind": "instructionAccountNode", "name": "ata", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Associated token account address to be created."], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "accountValueNode", "name": "owner" } }, { "kind": "pdaSeedValueNode", "name": "tokenProgram", "value": { "kind": "accountValueNode", "name": "tokenProgram" } }, { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "mint" } } ] } }, { "kind": "instructionAccountNode", "name": "owner", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Wallet address for the new associated token account."] }, { "kind": "instructionAccountNode", "name": "mint", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["The token mint for the new associated token account."] }, { "kind": "instructionAccountNode", "name": "systemProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["System program."], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "11111111111111111111111111111111" } }, { "kind": "instructionAccountNode", "name": "tokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["SPL Token program."], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 1 }, "defaultValueStrategy": "omitted" } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "name": "createAssociatedTokenIdempotent", "docs": [ "Creates an associated token account for the given wallet address and", "token mint, if it doesn't already exist. Returns an error if the", "account exists, but with a different owner." ], "optionalAccountStrategy": "programId" }, { "kind": "instructionNode", "accounts": [ { "kind": "instructionAccountNode", "name": "nestedAssociatedAccountAddress", "isWritable": true, "isSigner": false, "isOptional": false, "docs": [ "Nested associated token account, must be owned by `ownerAssociatedAccountAddress`." ], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "accountValueNode", "name": "ownerAssociatedAccountAddress" } }, { "kind": "pdaSeedValueNode", "name": "tokenProgram", "value": { "kind": "accountValueNode", "name": "tokenProgram" } }, { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "nestedTokenMintAddress" } } ] } }, { "kind": "instructionAccountNode", "name": "nestedTokenMintAddress", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Token mint for the nested associated token account."] }, { "kind": "instructionAccountNode", "name": "destinationAssociatedAccountAddress", "isWritable": true, "isSigner": false, "isOptional": false, "docs": ["Wallet's associated token account."], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "accountValueNode", "name": "walletAddress" } }, { "kind": "pdaSeedValueNode", "name": "tokenProgram", "value": { "kind": "accountValueNode", "name": "tokenProgram" } }, { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "nestedTokenMintAddress" } } ] } }, { "kind": "instructionAccountNode", "name": "ownerAssociatedAccountAddress", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Owner associated token account address, must be owned by `walletAddress`."], "defaultValue": { "kind": "pdaValueNode", "pda": { "kind": "pdaLinkNode", "name": "associatedToken" }, "seeds": [ { "kind": "pdaSeedValueNode", "name": "owner", "value": { "kind": "accountValueNode", "name": "walletAddress" } }, { "kind": "pdaSeedValueNode", "name": "tokenProgram", "value": { "kind": "accountValueNode", "name": "tokenProgram" } }, { "kind": "pdaSeedValueNode", "name": "mint", "value": { "kind": "accountValueNode", "name": "ownerTokenMintAddress" } } ] } }, { "kind": "instructionAccountNode", "name": "ownerTokenMintAddress", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["Token mint for the owner associated token account."] }, { "kind": "instructionAccountNode", "name": "walletAddress", "isWritable": true, "isSigner": true, "isOptional": false, "docs": ["Wallet address for the owner associated token account."] }, { "kind": "instructionAccountNode", "name": "tokenProgram", "isWritable": false, "isSigner": false, "isOptional": false, "docs": ["SPL Token program."], "defaultValue": { "kind": "publicKeyValueNode", "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" } } ], "arguments": [ { "kind": "instructionArgumentNode", "name": "discriminator", "type": { "kind": "numberTypeNode", "format": "u8", "endian": "le" }, "docs": [], "defaultValue": { "kind": "numberValueNode", "number": 2 }, "defaultValueStrategy": "omitted" } ], "discriminators": [ { "kind": "fieldDiscriminatorNode", "name": "discriminator", "offset": 0 } ], "name": "recoverNestedAssociatedToken", "docs": [ "Transfers from and closes a nested associated token account: an", "associated token account owned by an associated token account.", "", "The tokens are moved from the nested associated token account to the", "wallet's associated token account, and the nested account lamports are", "moved to the wallet.", "", "Note: Nested token accounts are an anti-pattern, and almost always", "created unintentionally, so this instruction should only be used to", "recover from errors." ], "optionalAccountStrategy": "programId" } ], "definedTypes": [], "errors": [ { "kind": "errorNode", "name": "invalidOwner", "code": 0, "message": "Associated token account owner does not match address derivation", "docs": ["InvalidOwner: Associated token account owner does not match address derivation"] } ], "name": "associatedToken", "prefix": "", "publicKey": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", "version": "1.1.1", "origin": "shank" } ], "standard": "codama", "version": "1.0.0" } ================================================ FILE: packages/dynamic-client/test/programs/mpl-token-metadata/create-with-resolvers.test.ts ================================================ import { findMasterEditionPda, findMetadataPda, getMetadataDecoder, TokenStandard, } from '@metaplex-foundation/mpl-token-metadata-kit'; import { address } from '@solana/addresses'; import { some } from '@solana/codecs'; import { beforeEach, describe, expect, test } from 'vitest'; import type { CreateArgs } from '../generated/mpl-token-metadata-idl-types'; import { SvmTestContext } from '../test-utils'; import { createMint } from '../token/token-test-utils'; import { loadMplProgram, programClient } from './helpers'; function buildFungibleArgs(): CreateArgs { return { createArgs: { __kind: 'v1', collection: null, collectionDetails: null, creators: null, decimals: null, isMutable: true, name: 'Test NFT', primarySaleHappened: false, printSupply: null, ruleSet: null, sellerFeeBasisPoints: 500, symbol: 'TST', tokenStandard: 'fungible', uri: 'https://example.com/metadata.json', uses: null, }, }; } describe('MPL Token Metadata: create with resolvers', () => { let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext({ defaultPrograms: true, sysvars: true }); loadMplProgram(ctx, programClient.programAddress); }); test('should auto-resolve splTokenProgram when resolveIsNonFungibleOrIsMintSigner returns true', async () => { const payer = await ctx.createFundedAccount(); const mintAuthority = await ctx.createFundedAccount(); const mint = await ctx.createAccount(); await createMint(ctx, payer, mint, mintAuthority); const [metadataPda] = await findMetadataPda({ mint }); const [masterEditionPda] = await findMasterEditionPda({ mint }); const expectedAccounts = [ metadataPda, masterEditionPda, mint, mintAuthority, payer, mintAuthority, ctx.SYSTEM_PROGRAM_ADDRESS, ctx.SYSVAR_INSTRUCTIONS_ADDRESS, address('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'), // from ifTrue branch ]; const ix = await programClient.methods .create(buildFungibleArgs()) .accounts({ authority: mintAuthority, masterEdition: masterEditionPda, mint, payer, // splTokenProgram omitted — should be auto-resolved via defaultValue resolver }) .signers(['mint']) .resolvers({ // conditionalValueNode -> resolveIsNonFungibleOrIsMintSigner -> ifTrue branch -> publicKeyValueNode resolveIsNonFungibleOrIsMintSigner: async () => await Promise.resolve(true), }) .instruction(); expect(ix.accounts?.length).toBe(9); expectedAccounts.forEach((expected, i) => { expect(expected, `Account mismatch at index ${i}`).toBe(ix.accounts?.[i].address); }); await ctx.sendInstruction(ix, [payer, mintAuthority, mint]); const metadataAccountInfo = ctx.requireEncodedAccount(metadataPda); const metadata = getMetadataDecoder().decode(metadataAccountInfo.data); expect(metadata.tokenStandard).toEqual(some(TokenStandard.Fungible)); }); test('should resolve splTokenProgram to programId when resolver returns false (optionalAccountStrategy=programId)', async () => { const payer = await ctx.createFundedAccount(); const mintAuthority = await ctx.createFundedAccount(); const mint = await ctx.createAccount(); await createMint(ctx, payer, mint, mintAuthority); const [masterEditionPda] = await findMasterEditionPda({ mint }); const ix = await programClient.methods .create(buildFungibleArgs()) .accounts({ authority: mintAuthority, masterEdition: masterEditionPda, mint, payer, }) .signers(['mint']) .resolvers({ resolveIsNonFungibleOrIsMintSigner: async () => await Promise.resolve(false), }) .instruction(); // resolver returns false -> ifFalse is undefined -> conditional returns null // optional optionalAccountStrategy=programId resolves to program ID expect(ix.accounts?.length).toBe(9); expect(ix.accounts?.[ix.accounts.length - 1].address).toBe(programClient.programAddress); await ctx.sendInstruction(ix, [payer, mintAuthority, mint]); const [metadataPda] = await findMetadataPda({ mint }); const metadataAccountInfo = ctx.requireEncodedAccount(metadataPda); const metadata = getMetadataDecoder().decode(metadataAccountInfo.data); expect(metadata.tokenStandard).toEqual(some(TokenStandard.Fungible)); }); test('should use user-provided account and bypass resolver', async () => { const payer = await ctx.createFundedAccount(); const splTokenProgramMock = await ctx.createAccount(); const mintAuthority = await ctx.createFundedAccount(); const mint = await ctx.createAccount(); await createMint(ctx, payer, mint, mintAuthority); const [masterEditionPda] = await findMasterEditionPda({ mint }); const ix = await programClient.methods .create(buildFungibleArgs()) .accounts({ authority: mintAuthority, masterEdition: masterEditionPda, mint, payer, splTokenProgram: splTokenProgramMock, }) .signers(['mint']) .resolvers({ // This resolver should not be called since splTokenProgram is explicitly provided resolveIsNonFungibleOrIsMintSigner: async () => { return await Promise.reject( new Error('Resolver should not be called for explicitly provided account'), ); }, }) .instruction(); expect(ix.accounts?.[ix.accounts.length - 1].address).toBe(splTokenProgramMock); await ctx.sendInstruction(ix, [payer, mintAuthority, mint]); const [metadataPda] = await findMetadataPda({ mint }); const metadataAccountInfo = ctx.requireEncodedAccount(metadataPda); const metadata = getMetadataDecoder().decode(metadataAccountInfo.data); expect(metadata.tokenStandard).toEqual(some(TokenStandard.Fungible)); }); test('should work without calling .resolvers()', async () => { const payer = await ctx.createFundedAccount(); const mintAuthority = await ctx.createFundedAccount(); const mint = await ctx.createAccount(); await createMint(ctx, payer, mint, mintAuthority); const [masterEditionPda] = await findMasterEditionPda({ mint }); const ix = await programClient.methods .create(buildFungibleArgs()) .accounts({ authority: mintAuthority, masterEdition: masterEditionPda, mint, payer, splTokenProgram: null, // auto resolution via optionalAccountStrategy into programId }) .signers(['mint']) .instruction(); expect(ix.programAddress).toBe(programClient.programAddress); expect(ix.accounts?.length).toBe(9); expect(ix.accounts?.[ix.accounts.length - 1].address).toBe(programClient.programAddress); await ctx.sendInstruction(ix, [payer, mintAuthority, mint]); const [metadataPda] = await findMetadataPda({ mint }); const metadataAccountInfo = ctx.requireEncodedAccount(metadataPda); const metadata = getMetadataDecoder().decode(metadataAccountInfo.data); expect(metadata.tokenStandard).toEqual(some(TokenStandard.Fungible)); }); test('should fallback to optionalAccountStrategy when no resolver and no account provided', async () => { const payer = await ctx.createFundedAccount(); const mintAuthority = await ctx.createFundedAccount(); const mint = await ctx.createAccount(); await createMint(ctx, payer, mint, mintAuthority); const [masterEditionPda] = await findMasterEditionPda({ mint }); // undefined splTokenProgram triggers defaultValue auto-resolution. // defaultValue is conditionalValueNode with undefined ifFalse branch // Without resolvers provided, condition should choose ifFalse branch // Optional account should be resolved into programId via optionalAccountStrategy const ix = await programClient.methods .create(buildFungibleArgs()) .accounts({ authority: mintAuthority, masterEdition: masterEditionPda, mint, payer, }) .signers(['mint']) .instruction(); expect(ix.accounts?.length).toBe(9); expect(ix.accounts?.[ix.accounts.length - 1].address).toBe(programClient.programAddress); await ctx.sendInstruction(ix, [payer, mintAuthority, mint]); const [metadataPda] = await findMetadataPda({ mint }); const metadataAccountInfo = ctx.requireEncodedAccount(metadataPda); const metadata = getMetadataDecoder().decode(metadataAccountInfo.data); expect(metadata.tokenStandard).toEqual(some(TokenStandard.Fungible)); }); }); ================================================ FILE: packages/dynamic-client/test/programs/mpl-token-metadata/create.test.ts ================================================ import { findMasterEditionPda, findMetadataPda, getMetadataDecoder, TokenStandard, } from '@metaplex-foundation/mpl-token-metadata-kit'; import { none, some } from '@solana/codecs'; import { beforeEach, describe, expect, test } from 'vitest'; import type { CreateArgs } from '../generated/mpl-token-metadata-idl-types'; import { SvmTestContext } from '../test-utils'; import { createMint } from '../token/token-test-utils'; import { loadMplProgram, programClient } from './helpers'; describe('MPL Token Metadata: create', () => { let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext({ defaultPrograms: true, sysvars: true }); loadMplProgram(ctx, programClient.programAddress); }); test('should construct a valid create instruction', async () => { const payer = await ctx.createFundedAccount(); const mintAuthority = await ctx.createFundedAccount(); const mint = await ctx.createAccount(); await createMint(ctx, payer, mint, mintAuthority); const [metadataPda] = await findMetadataPda({ mint }); const [masterEditionPda] = await findMasterEditionPda({ mint }); const expectedAccounts = [ metadataPda, masterEditionPda, mint, mintAuthority, payer, mintAuthority, ctx.SYSTEM_PROGRAM_ADDRESS, ctx.SYSVAR_INSTRUCTIONS_ADDRESS, programClient.programAddress, ]; const args: CreateArgs = { createArgs: { __kind: 'v1', collection: null, collectionDetails: null, creators: null, decimals: null, isMutable: true, name: 'Test NFT', primarySaleHappened: false, printSupply: null, ruleSet: null, sellerFeeBasisPoints: 500, symbol: 'TST', tokenStandard: 'fungible', uri: 'https://example.com/metadata.json', uses: null, }, }; const ix = await programClient.methods .create(args) .accounts({ authority: mintAuthority, masterEdition: masterEditionPda, mint, payer, splTokenProgram: null, // auto-derived via optionalAccountStrategy into programClient.programAddress // metadata: metadataPda, // auto-derived pda, can be omitted // updateAuthority: mintAuthority, // auto-derived into "authority" , can be omitted }) .instruction(); expect(ix.accounts?.length).toBe(9); expectedAccounts.forEach((expected, i) => { expect(expected, `Account mismatch at index ${i}`).toBe(ix.accounts?.[i].address); }); await ctx.sendInstruction(ix, [payer, mintAuthority]); const metadataAccountInfo = ctx.requireEncodedAccount(metadataPda); const metadata = getMetadataDecoder().decode(metadataAccountInfo.data); expect(metadata.name).toBe(args.createArgs.name); expect(metadata.symbol).toBe(args.createArgs.symbol); expect(metadata.uri).toBe(args.createArgs.uri); expect(metadata.sellerFeeBasisPoints).toBe(args.createArgs.sellerFeeBasisPoints); expect(metadata.primarySaleHappened).toBe(args.createArgs.primarySaleHappened); expect(metadata.isMutable).toBe(args.createArgs.isMutable); expect(metadata.tokenStandard).toEqual(some(TokenStandard.Fungible)); expect(metadata.collection).toEqual(none()); expect(metadata.collectionDetails).toEqual(none()); expect(metadata.creators).toEqual(none()); expect(metadata.uses).toEqual(none()); }); test('should throw ValidationError for invalid sellerFeeBasisPoints [amountValueNode]', async () => { const payer = await ctx.createFundedAccount(); const mintAuthority = await ctx.createFundedAccount(); const mint = await ctx.createAccount(); await createMint(ctx, payer, mint, mintAuthority); const [masterEditionPda] = await findMasterEditionPda({ mint }); const args: CreateArgs = { createArgs: { __kind: 'v1', collection: null, collectionDetails: null, creators: null, decimals: null, isMutable: true, name: 'Test NFT', primarySaleHappened: false, printSupply: null, ruleSet: null, sellerFeeBasisPoints: 'not a number' as unknown as number, // invalid value for amountValueNode symbol: 'TST', tokenStandard: 'fungible', uri: 'https://example.com/metadata.json', uses: null, }, }; await expect( programClient.methods .create(args) .accounts({ authority: mintAuthority, masterEdition: masterEditionPda, mint, payer, splTokenProgram: null, }) .instruction(), ).rejects.toThrowError(/Invalid argument "createArgs"/); }); test('should construct a create instruction with mint as signer and provided TokenProgram', async () => { const payer = await ctx.createFundedAccount(); const mintAuthority = await ctx.createFundedAccount(); const mint = await ctx.createAccount(); await createMint(ctx, payer, mint, mintAuthority); const [metadataPda] = await findMetadataPda({ mint }); const [masterEditionPda] = await findMasterEditionPda({ mint }); const expectedAccounts = [ metadataPda, masterEditionPda, mint, mintAuthority, payer, mintAuthority, ctx.SYSTEM_PROGRAM_ADDRESS, ctx.SYSVAR_INSTRUCTIONS_ADDRESS, ctx.TOKEN_PROGRAM_ADDRESS, ]; const args: CreateArgs = { createArgs: { __kind: 'v1', collection: null, collectionDetails: null, creators: null, decimals: null, isMutable: true, name: 'Test NFT', primarySaleHappened: false, printSupply: null, ruleSet: null, sellerFeeBasisPoints: 500n, symbol: 'TST', tokenStandard: 'fungible', uri: 'https://example.com/metadata.json', uses: null, }, }; const ix = await programClient.methods .create(args) .accounts({ authority: mintAuthority, masterEdition: masterEditionPda, mint, payer, splTokenProgram: ctx.TOKEN_PROGRAM_ADDRESS, // explicitly provide to skip auto-derivation with ResolverValueNode which is not supported yet }) .signers(['mint']) .instruction(); expect(ix.accounts?.length).toBe(9); expectedAccounts.forEach((expected, i) => { expect(expected, `Account mismatch at index ${i}`).toBe(ix.accounts?.[i].address); }); await ctx.sendInstruction(ix, [payer, mintAuthority, mint]); const metadataAccountInfo = ctx.requireEncodedAccount(metadataPda); const metadata = getMetadataDecoder().decode(metadataAccountInfo.data); expect(metadata.name).toBe(args.createArgs.name); expect(metadata.symbol).toBe(args.createArgs.symbol); expect(metadata.uri).toBe(args.createArgs.uri); expect(metadata.sellerFeeBasisPoints).toBe(Number(args.createArgs.sellerFeeBasisPoints)); expect(metadata.primarySaleHappened).toBe(args.createArgs.primarySaleHappened); expect(metadata.isMutable).toBe(args.createArgs.isMutable); expect(metadata.tokenStandard).toEqual(some(TokenStandard.Fungible)); expect(metadata.collection).toEqual(none()); expect(metadata.collectionDetails).toEqual(none()); expect(metadata.creators).toEqual(none()); expect(metadata.uses).toEqual(none()); }); }); ================================================ FILE: packages/dynamic-client/test/programs/mpl-token-metadata/helpers.ts ================================================ import path from 'node:path'; import { type Address } from '@solana/addresses'; import type { MplTokenMetadataProgramClient } from '../generated/mpl-token-metadata-idl-types'; import { createTestProgramClient, SvmTestContext } from '../test-utils'; export const programClient = createTestProgramClient('mpl-token-metadata-idl.json'); /** * Loads compiled MPL program binary located at '../dumps/mpl-token-metadata.so' into the test context at the specified program address. */ export function loadMplProgram(ctx: SvmTestContext, programAddress: Address): void { const programPath = path.resolve(__dirname, '..', 'dumps', 'mpl-token-metadata.so'); ctx.loadProgram(programAddress, programPath); } ================================================ FILE: packages/dynamic-client/test/programs/pmp/allocate.test.ts ================================================ import { type Address } from '@solana/addresses'; import type { Some } from '@solana/codecs'; import { AccountDiscriminator } from '@solana-program/program-metadata'; import { beforeEach, describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { decodeBufferAccount, loadPmpProgram, programClient, setupCanonicalPda, setupNonCanonicalPda } from './helpers'; describe('Program Metadata: allocate', () => { let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext(); loadPmpProgram(ctx, programClient.programAddress); }); test('should allocate with seed null', async () => { const bufferAndAuthority = await ctx.createFundedAccount(); const ix = await programClient.methods .allocate({ seed: null }) .accounts({ authority: bufferAndAuthority, buffer: bufferAndAuthority, program: null, programData: null, }) .instruction(); await ctx.sendInstruction(ix, [bufferAndAuthority]); const account = ctx.requireEncodedAccount(bufferAndAuthority); const buffer = decodeBufferAccount(account.data); expect(buffer.discriminator).toBe(AccountDiscriminator.Buffer); expect(buffer.canonical).toBe(false); expect(buffer.program).toEqual({ __option: 'None' }); expect((buffer.authority as Some
).value).toBe(bufferAndAuthority); }); test('should allocate canonical PDA buffer', async () => { const seed = 'idl'; const { authority, programAddress, programDataAddress, pda: bufferPda } = await setupCanonicalPda(ctx, seed); const ix = await programClient.methods .allocate({ seed }) .accounts({ authority, buffer: bufferPda, program: programAddress, programData: programDataAddress, }) .instruction(); await ctx.sendInstruction(ix, [authority]); const account = ctx.requireEncodedAccount(bufferPda); expect(account.owner).toBe(programClient.programAddress); expect(account.data.length).gt(0); const buffer = decodeBufferAccount(account.data); expect(buffer.discriminator).toBe(AccountDiscriminator.Buffer); expect(buffer.canonical).toBe(true); expect(buffer.program).toEqual({ __option: 'Some', value: programAddress }); expect(buffer.authority).toEqual({ __option: 'Some', value: authority }); expect(buffer.seed).toBe(seed); }); test('should allocate non-canonical PDA buffer', async () => { const seed = 'idl'; const { authority, programAddress, programDataAddress, pda: bufferPda } = await setupNonCanonicalPda(ctx, seed); const ix = await programClient.methods .allocate({ seed }) .accounts({ authority, buffer: bufferPda, program: programAddress, programData: programDataAddress, }) .instruction(); await ctx.sendInstruction(ix, [authority]); const account = ctx.requireEncodedAccount(bufferPda); expect(account.owner).toBe(programClient.programAddress); expect(account.data.length).gt(0); const buffer = decodeBufferAccount(account.data); expect(buffer.discriminator).toBe(AccountDiscriminator.Buffer); expect(buffer.canonical).toBe(false); expect(buffer.program).toEqual({ __option: 'Some', value: programAddress }); expect(buffer.authority).toEqual({ __option: 'Some', value: authority }); expect(buffer.seed).toBe(seed); }); }); ================================================ FILE: packages/dynamic-client/test/programs/pmp/close.test.ts ================================================ import { type Address } from '@solana/addresses'; import { beforeEach, describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { allocateBufferAccount, decodeBufferAccount, initializeCanonicalMetadata, loadPmpProgram, programClient, setupCanonicalPda, } from './helpers'; describe('Program Metadata: close', () => { let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext(); loadPmpProgram(ctx, programClient.programAddress); }); test('should close canonical PDA buffer', async () => { const destination = await ctx.createFundedAccount(); const { authority, programAddress, programDataAddress, pda: bufferPda } = await setupCanonicalPda(ctx); const allocateIx = await programClient.methods .allocate({ seed: 'idl' }) .accounts({ authority, buffer: bufferPda, program: programAddress, programData: programDataAddress, }) .instruction(); await ctx.sendInstruction(allocateIx, [authority]); const bufferAccount = ctx.requireEncodedAccount(bufferPda); expect(bufferAccount).not.toBeNull(); const destinationBalanceBefore = ctx.getBalanceOrZero(destination); const closeIx = await programClient.methods .close() .accounts({ account: bufferPda, authority, destination, program: programAddress, programData: programDataAddress, }) .instruction(); await ctx.sendInstruction(closeIx, [authority]); const closedAccount = ctx.fetchEncodedAccount(bufferPda); expect(closedAccount).toBeNull(); const destinationBalanceAfter = ctx.getBalanceOrZero(destination); expect(destinationBalanceAfter).toBeGreaterThan(destinationBalanceBefore); }); test('should close mutable metadata', async () => { const destination = await ctx.createFundedAccount(); const { authority, programAddress, programDataAddress, pda: metadataPda, } = await initializeCanonicalMetadata(ctx); const destinationBalanceBefore = ctx.getBalanceOrZero(destination); const closeIx = await programClient.methods .close() .accounts({ account: metadataPda, authority, destination, program: programAddress, programData: programDataAddress, }) .instruction(); await ctx.sendInstruction(closeIx, [authority]); const closedAccount = ctx.fetchEncodedAccount(metadataPda); expect(closedAccount).toBeNull(); const destinationBalanceAfter = ctx.getBalanceOrZero(destination); expect(destinationBalanceAfter).toBeGreaterThan(destinationBalanceBefore); }); test('should close buffer account', async () => { const feePayer = await ctx.createFundedAccount(); const destination = await ctx.createFundedAccount(); const { bufferAccount } = await allocateBufferAccount(ctx); const buffer = ctx.requireEncodedAccount(bufferAccount); const decoded = decodeBufferAccount(buffer.data); expect(decoded.canonical).toBe(false); const destinationBalanceBefore = ctx.getBalanceOrZero(destination); const closeIx = await programClient.methods .close() .accounts({ account: bufferAccount, authority: bufferAccount, destination, program: null, programData: null, }) .instruction(); await ctx.sendInstruction(closeIx, [feePayer, bufferAccount]); const destinationBalanceAfter = ctx.getBalanceOrZero(destination); expect(destinationBalanceAfter).toBeGreaterThan(destinationBalanceBefore); const closedAccount = ctx.fetchEncodedAccount(bufferAccount); expect(closedAccount).toBeNull(); }); test('should throw AccountError when destination is missing', async () => { const authority = await ctx.createFundedAccount(); await expect( programClient.methods .close() .accounts({ account: authority, authority, destination: undefined as unknown as Address, program: null, programData: null, }) .instruction(), ).rejects.toThrow(/Missing account \[destination\]/); }); }); ================================================ FILE: packages/dynamic-client/test/programs/pmp/extend.test.ts ================================================ import { type Address } from '@solana/addresses'; import { beforeEach, describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { allocateBufferAccount, decodeMetadataAccount, initializeCanonicalMetadata, loadPmpProgram, programClient, } from './helpers'; describe('Program Metadata: extend', () => { let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext(); loadPmpProgram(ctx, programClient.programAddress); }); test('should extend buffer capacity', async () => { const feePayer = await ctx.createFundedAccount(); const { bufferAccount } = await allocateBufferAccount(ctx); const accountBefore = ctx.requireEncodedAccount(bufferAccount); const sizeBefore = accountBefore.data.length; const extendLength = 500; const extendIx = await programClient.methods .extend({ length: extendLength }) .accounts({ account: bufferAccount, authority: bufferAccount, program: null, programData: null, }) .instruction(); await ctx.sendInstruction(extendIx, [feePayer, bufferAccount]); const accountAfter = ctx.requireEncodedAccount(bufferAccount); expect(accountAfter.data.length).toBe(sizeBefore + extendLength); }); test('should extend canonical metadata capacity', async () => { const { authority, programAddress, programDataAddress, pda: metadataPda, } = await initializeCanonicalMetadata(ctx); const accountBefore = ctx.requireEncodedAccount(metadataPda); const sizeBefore = accountBefore.data.length; const extendLength = 500; const extendIx = await programClient.methods .extend({ length: extendLength }) .accounts({ account: metadataPda, authority, program: programAddress, programData: programDataAddress, }) .instruction(); await ctx.sendInstruction(extendIx, [authority]); const accountAfter = ctx.requireEncodedAccount(metadataPda); expect(accountAfter.data.length).toBe(sizeBefore + extendLength); const metadata = decodeMetadataAccount(accountAfter.data); expect(metadata.canonical).toBe(true); }); test('should throw ArgumentError when length argument is missing', async () => { const authority = await ctx.createFundedAccount(); await expect( programClient.methods .extend({ length: undefined as unknown as number }) .accounts({ account: authority, authority, program: null, programData: null, }) .instruction(), ).rejects.toThrow(/Invalid argument "length"/); }); test('should throw AccountError when required account is missing', async () => { await expect( programClient.methods .extend({ length: 100 }) .accounts({ account: undefined as unknown as Address, authority: undefined as unknown as Address, program: null, programData: null, }) .instruction(), ).rejects.toThrow(/Missing account \[account\]/); }); }); ================================================ FILE: packages/dynamic-client/test/programs/pmp/helpers.ts ================================================ import fs from 'node:fs'; import path from 'node:path'; import { type Address, getAddressEncoder, getProgramDerivedAddress } from '@solana/addresses'; import { getOptionEncoder, getStructEncoder, getU32Encoder, getU64Encoder, none, some } from '@solana/codecs'; import { type Buffer as PmpBuffer, getBufferDecoder, getMetadataDecoder, type Metadata as PmpMetadata, } from '@solana-program/program-metadata'; import type { SvmTestContext } from '../../svm-test-context'; import type { ProgramMetadataProgramClient } from '../generated/pmp-idl-types'; import { createTestProgramClient } from '../test-utils'; export const programClient = createTestProgramClient('pmp-idl.json'); export const PMP_PROGRAM_ID = programClient.programAddress; export const exampleProgramPath = path.join(__dirname, '../dumps/pmp.so'); /** * Creates a 16-byte seed buffer from a string for PDA derivation. * * PMP seeds are fixed-size 16-byte UTF-8 strings. If the input string is shorter * than 16 bytes, then we want to pad it with zeros. If longer, it's truncated. * * @param seed - The seed string (max 16 bytes UTF-8) * @returns A 16-byte Uint8Array */ export function encodeSeedForPda(seed: string): Uint8Array { const seedBytes = new TextEncoder().encode(seed); const buffer = new Uint8Array(16); buffer.set(seedBytes.slice(0, 16)); // Copy up to 16 bytes return buffer; } export function decodeBufferAccount(data: Uint8Array): PmpBuffer { const decoder = getBufferDecoder(); return decoder.decode(data); } export function decodeMetadataAccount(data: Uint8Array): PmpMetadata { const decoder = getMetadataDecoder(); return decoder.decode(data); } /** * Loads compiled PMP program binary located at '../dumps/pmp.so' into the test context at the specified program address. */ export function loadPmpProgram(ctx: SvmTestContext, programAddress: Address): void { const programPath = path.resolve(__dirname, '..', 'dumps', 'pmp.so'); ctx.loadProgram(programAddress, programPath); } /** Helper for creating canonical Metadata. */ export async function initializeCanonicalMetadata(ctx: SvmTestContext, options?: { data?: Uint8Array; seed?: string }) { const seed = options?.seed ?? 'idl'; const data = options?.data ?? new TextEncoder().encode('{"name":"test"}'); const result = await setupCanonicalPda(ctx, seed); const initIx = await programClient.methods .initialize({ compression: 'none', data, dataSource: 'direct', encoding: 'utf8', format: 'json', seed, }) .accounts({ authority: result.authority, program: result.programAddress, programData: result.programDataAddress, }) .instruction(); await ctx.sendInstruction(initIx, [result.authority]); return result; } /** Helper for creating non-canonical Metadata. */ export async function initializeNonCanonicalMetadata( ctx: SvmTestContext, options?: { data?: Uint8Array; seed?: string }, ) { const seed = options?.seed ?? 'idl'; const data = options?.data ?? new TextEncoder().encode('non-canonical data'); const result = await setupNonCanonicalPda(ctx, seed); const initIx = await programClient.methods .initialize({ compression: 'none', data, dataSource: 'direct', encoding: 'utf8', format: 'json', seed, }) .accounts({ authority: result.authority, program: result.programAddress, programData: null, }) .instruction(); await ctx.sendInstruction(initIx, [result.authority]); return result; } /** * Helper to create common required accounts for canonical PMP use cases. * - Creates Upgradable Program Accounts for LiteSVM. * - Creates a canonical PDA (program upgradeAuthority), i.e [programAddress, seed]. */ export async function setupCanonicalPda(ctx: SvmTestContext, seed = 'idl') { const authority = await ctx.createFundedAccount(); const testProgramAddress = await ctx.createAccount(); const { programAddress, programDataAddress } = await setUpgradeableProgramAccounts( ctx, exampleProgramPath, testProgramAddress, authority, ); const pda = await deriveCanonicalPda(programAddress, seed); ctx.airdropToAddress(pda, BigInt(10_000_000_000)); return { authority, pda, programAddress, programDataAddress }; } /** * Helper to create common required accounts for non-canonical PMP use cases. * - Creates Upgradable Program Accounts for LiteSVM. * - Creates a non-canonical PDA (arbitrary authority), i.e [programAddress, authority, seed]. */ export async function setupNonCanonicalPda(ctx: SvmTestContext, seed = 'idl') { const authority = await ctx.createFundedAccount(); const programDataAuthority = await ctx.createFundedAccount(); const testProgramAddress = await ctx.createAccount(); const { programAddress, programDataAddress } = await setUpgradeableProgramAccounts( ctx, exampleProgramPath, testProgramAddress, programDataAuthority, ); const pda = await deriveNonCanonicalPda(programAddress, authority, seed); ctx.airdropToAddress(pda, BigInt(10_000_000_000)); return { authority, pda, programAddress, programDataAddress, programDataAuthority }; } /** * Manually creates BPF Loader Upgradeable accounts for a program in LiteSVM. * since LiteSVM's loadProgram() doesn't create ProgramData accounts * * This allows testing canonical vs non-canonical scenarios: * - Canonical: authority matches ProgramData.upgrade_authority * - Non-canonical: authority does NOT match ProgramData.upgrade_authority * * How it works: * - Derives the ProgramData address (PDA with seeds: [program_address]) * - Reads the program bytecode from file * - Creates ProgramData account with custom authority + bytecode * - Creates Program account pointing to ProgramData * - Both accounts are owned by BPF Loader Upgradeable * * @param ctx - Test context * @param programBinaryPath - Path to program .so file * @param programAddress - Address of the program * @param upgradeAuthority - Authority to set in ProgramData account * @returns { programAddress, programDataAddress } */ export async function setUpgradeableProgramAccounts( ctx: SvmTestContext, programBinaryPath: string, programAddress: Address, upgradeAuthority: Address, ): Promise<{ programAddress: Address; programDataAddress: Address }> { const addressEncoder = getAddressEncoder(); const [programDataAddress] = await getProgramDerivedAddress({ programAddress: ctx.BPF_LOADER_UPGRADEABLE, seeds: [addressEncoder.encode(programAddress)], }); const programDataAccountBytes = encodeProgramDataAccount(upgradeAuthority); const programBytes = fs.readFileSync(programBinaryPath); const programDataAccountData = new Uint8Array([...programDataAccountBytes, ...programBytes]); const rentExemptBalance = ctx.getMinimumBalanceForRentExemption(BigInt(programDataAccountData.length)); ctx.setAccount(programDataAddress, { data: programDataAccountData, executable: false, lamports: rentExemptBalance, owner: ctx.BPF_LOADER_UPGRADEABLE, }); const programAccountBytes = encodeProgramAccount(programDataAddress); ctx.setAccount(programAddress, { data: Uint8Array.from(programAccountBytes), executable: true, lamports: rentExemptBalance, owner: ctx.BPF_LOADER_UPGRADEABLE, }); return { programAddress, programDataAddress }; } /** Creates ProgramData Account for BPF Loader Upgradeable. */ function encodeProgramDataAccount(authority: Address | null) { const encoder = getStructEncoder([ ['discriminator', getU32Encoder()], ['slot', getU64Encoder()], ['authority', getOptionEncoder(getAddressEncoder())], ]); return encoder.encode({ authority: authority ? some(authority) : none(), discriminator: 3, slot: 0n, }); } /** Creates a Program Account for BPF Loader Upgradeable. */ function encodeProgramAccount(programDataAddress: Address) { const encoder = getStructEncoder([ ['discriminator', getU32Encoder()], ['programData', getAddressEncoder()], ]); return encoder.encode({ discriminator: 2, programData: programDataAddress, }); } /** Helper for allocating Buffer. Used for extending, closing or adding data */ export async function allocateBufferAccount(ctx: SvmTestContext) { const bufferAccount = await ctx.createFundedAccount(); const allocateIx = await programClient.methods .allocate({ seed: null }) .accounts({ authority: bufferAccount, buffer: bufferAccount, program: null, programData: null, }) .instruction(); await ctx.sendInstruction(allocateIx, [bufferAccount]); return { bufferAccount }; } /** Derives a canonical PDA (upgradeAuthority), i.e [programAddress, seed]. */ export async function deriveCanonicalPda(programAddress: Address, seed: string) { const seed16Bytes = encodeSeedForPda(seed); const addressEncoder = getAddressEncoder(); const [pda] = await getProgramDerivedAddress({ programAddress: programClient.programAddress, seeds: [addressEncoder.encode(programAddress), seed16Bytes], }); return pda; } /** Derives a non-canonical PDA (arbitrary authority), i.e [programAddress, authority, seed]. */ export async function deriveNonCanonicalPda(programAddress: Address, authority: Address, seed: string) { const seed16Bytes = encodeSeedForPda(seed); const addressEncoder = getAddressEncoder(); const [pda] = await getProgramDerivedAddress({ programAddress: programClient.programAddress, seeds: [addressEncoder.encode(programAddress), addressEncoder.encode(authority), seed16Bytes], }); return pda; } ================================================ FILE: packages/dynamic-client/test/programs/pmp/initialize.test.ts ================================================ import { type Address } from '@solana/addresses'; import type { Some } from '@solana/codecs'; import { AccountDiscriminator, Compression, DataSource, Encoding, Format } from '@solana-program/program-metadata'; import { beforeEach, describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { decodeBufferAccount, decodeMetadataAccount, loadPmpProgram, PMP_PROGRAM_ID, programClient, setupCanonicalPda, setupNonCanonicalPda, } from './helpers'; describe('Program Metadata: initialize', () => { let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext(); loadPmpProgram(ctx, programClient.programAddress); }); test('should initialize canonical metadata with direct data (ifTrue condition branch)', async () => { const seed = 'idl'; const { authority, programAddress, programDataAddress, pda: metadataPda } = await setupCanonicalPda(ctx, seed); const testData = new TextEncoder().encode('{"name":"test"}'); const expectedAccounts = [ metadataPda, authority, programAddress, programDataAddress, ctx.SYSTEM_PROGRAM_ADDRESS, ]; const ix = await programClient.methods .initialize({ compression: 'none', data: testData, dataSource: 'direct', encoding: 'utf8', format: 'json', seed, }) .accounts({ authority, program: programAddress, programData: programDataAddress, }) .instruction(); expect(ix.accounts?.length).toBe(5); ix.accounts?.forEach((ixAccount, i) => { expect(expectedAccounts[i], `Invalid account: [${i}]`).toBe(ixAccount.address); }); await ctx.sendInstruction(ix, [authority]); const account = ctx.requireEncodedAccount(metadataPda); expect(account.owner).toBe(PMP_PROGRAM_ID); const metadata = decodeMetadataAccount(account.data); expect(metadata.canonical).toBe(true); expect(metadata.program).toBe(programAddress); // Canonical metadata stores authority as zero (None) expect(metadata.authority).toEqual({ __option: 'None' }); expect(metadata.seed).toBe(seed); const writtenData = metadata.data.slice(0, testData.length); expect(writtenData).toEqual(testData); }); test('should initialize non-canonical metadata (ifFalse condition branch)', async () => { const seed = 'idl'; const { authority, programAddress, pda: metadataPda } = await setupNonCanonicalPda(ctx, seed); const testData = new TextEncoder().encode('non-canonical data'); const expectedAccounts = [ metadataPda, authority, programAddress, programClient.programAddress, // with "programId" optionalAccountStrategy address is resolved to root.programId ctx.SYSTEM_PROGRAM_ADDRESS, ]; const ix = await programClient.methods .initialize({ compression: 'none', data: testData, dataSource: 'direct', encoding: 'utf8', format: 'json', seed, }) .accounts({ authority, program: programAddress, programData: null, // this should use ifFalse branch in conditionalValueNode }) .instruction(); expect(ix.accounts?.length).toBe(5); ix.accounts?.forEach((ixAccount, i) => { expect(expectedAccounts[i], `Invalid account: [${i}]`).toBe(ixAccount.address); }); await ctx.sendInstruction(ix, [authority]); const account = ctx.requireEncodedAccount(metadataPda); expect(account.owner).toBe(PMP_PROGRAM_ID); const metadata = decodeMetadataAccount(account.data); expect(metadata.discriminator).toBe(AccountDiscriminator.Metadata); expect(metadata.canonical).toBe(false); expect(metadata.program).toBe(programAddress); expect((metadata.authority as Some
).value).toBe(authority); expect(metadata.seed).toBe(seed); const writtenData = metadata.data.slice(0, testData.length); expect(writtenData).toEqual(testData); }); test('should resolve optional null system_program account according on optionalAccountStrategy', async () => { const seed = 'idl'; const { authority, programAddress, programDataAddress, pda: metadataPda } = await setupCanonicalPda(ctx, seed); const testData = new TextEncoder().encode('{"name":"test"}'); const expectedAccounts = [ metadataPda, authority, programAddress, programDataAddress, programClient.programAddress, // expect root.programAddress based on optionalAccountStrategy ]; const ix = await programClient.methods .initialize({ compression: 'none', data: testData, dataSource: 'direct', encoding: 'utf8', format: 'json', seed, }) .accounts({ authority, program: programAddress, programData: programDataAddress, system: null, // explicit null should resolve to root.programAddress }) .instruction(); expect(ix.accounts?.length).toBe(5); ix.accounts?.forEach((ixAccount, i) => { expect(expectedAccounts[i], `Invalid account: [${i}]`).toBe(ixAccount.address); }); }); test('should initialize metadata from pre-allocated buffer', async () => { const seed = 'idl'; const { authority, programAddress, programDataAddress, pda: metadataPda } = await setupCanonicalPda(ctx, seed); // Allocate the metadata PDA as a canonical buffer const allocateIx = await programClient.methods .allocate({ seed }) .accounts({ authority, buffer: metadataPda, program: programAddress, programData: programDataAddress, }) .instruction(); // Write data to the buffer at the metadata PDA address const testData = new TextEncoder().encode('{"from":"buffer"}'); const writeIx = await programClient.methods .write({ data: testData, offset: 0 }) .accounts({ authority, buffer: metadataPda, sourceBuffer: null, }) .instruction(); await ctx.sendInstructions([allocateIx, writeIx], [authority]); // Verify the buffer was written at the metadata PDA const bufferAccount = ctx.requireEncodedAccount(metadataPda); const buffer = decodeBufferAccount(bufferAccount.data); expect(buffer.discriminator).toBe(AccountDiscriminator.Buffer); // Now initialize — the program sees the Buffer discriminator and uses existing data const initializeIx = await programClient.methods .initialize({ compression: 'none', data: null, dataSource: 'direct', encoding: 'utf8', format: 'json', seed, }) .accounts({ authority, program: programAddress, programData: programDataAddress, }) .instruction(); await ctx.sendInstruction(initializeIx, [authority]); const account = ctx.requireEncodedAccount(metadataPda); expect(account.owner).toBe(PMP_PROGRAM_ID); const metadata = decodeMetadataAccount(account.data); expect(metadata.discriminator).toBe(AccountDiscriminator.Metadata); expect(metadata.canonical).toBe(true); expect(metadata.program).toBe(programAddress); expect(metadata.authority).toEqual({ __option: 'None' }); const writtenData = metadata.data.slice(0, testData.length); expect(writtenData).toEqual(testData); }); test('should initialize with different encoding and format', async () => { const seed = 'config'; const { authority, programAddress, programDataAddress, pda: metadataPda } = await setupCanonicalPda(ctx, seed); const testData = new TextEncoder().encode('dG9tbCBkYXRh'); const ix = await programClient.methods .initialize({ compression: 'zlib', data: testData, dataSource: 'url', encoding: 'base64', format: 'toml', seed, }) .accounts({ authority, program: programAddress, programData: programDataAddress, }) .instruction(); await ctx.sendInstruction(ix, [authority]); const account = ctx.requireEncodedAccount(metadataPda); expect(account.owner).toBe(PMP_PROGRAM_ID); const metadata = decodeMetadataAccount(account.data); expect(metadata.discriminator).toBe(AccountDiscriminator.Metadata); expect(metadata.canonical).toBe(true); expect(metadata.encoding).toBe(Encoding.Base64); expect(metadata.compression).toBe(Compression.Zlib); expect(metadata.format).toBe(Format.Toml); expect(metadata.dataSource).toBe(DataSource.Url); const writtenData = metadata.data.slice(0, testData.length); expect(writtenData).toEqual(testData); }); test('should throw AccountError when authority is missing for non-canonical metadata', async () => { const testProgramAddress = await ctx.createAccount(); await expect( programClient.methods .initialize({ compression: 'none', data: null, dataSource: 'direct', encoding: 'utf8', format: 'json', seed: 'idl', }) .accounts({ // Simulate invalid required authority account authority: undefined as unknown as Address, program: testProgramAddress, programData: null, }) .instruction(), ).rejects.toThrow(/Missing account \[authority\]/); }); test('should throw AccountError when required program account is missing', async () => { const authority = await ctx.createFundedAccount(); await expect( programClient.methods .initialize({ compression: 'none', data: null, dataSource: 'direct', encoding: 'utf8', format: 'json', seed: 'idl', }) .accounts({ authority, // Simulate invalid required program account program: undefined as unknown as Address, programData: null, }) .instruction(), ).rejects.toThrow(/Missing account \[program\]/); }); test('should throw ArgumentError when missing required seed argument', async () => { const authority = await ctx.createFundedAccount(); const testProgramAddress = await ctx.createAccount(); await expect( programClient.methods .initialize({ compression: 'none', data: null, dataSource: 'direct', encoding: 'utf8', format: 'json', // Simulate invalid seed seed: undefined as unknown as string, }) .accounts({ authority, program: testProgramAddress, programData: null, }) .instruction(), ).rejects.toThrow(/Invalid argument "seed", value: undefined/); }); }); ================================================ FILE: packages/dynamic-client/test/programs/pmp/pdas.test.ts ================================================ import { beforeEach, describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { deriveCanonicalPda, deriveNonCanonicalPda, loadPmpProgram, programClient, setupCanonicalPda, setupNonCanonicalPda, } from './helpers'; describe('Program Metadata: pdas', () => { let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext(); loadPmpProgram(ctx, programClient.programAddress); }); describe('canonical', () => { test('should derive canonical PDA matching manual derivation', async () => { const programAddress = await ctx.createAccount(); const seed = 'idl'; const [pdaFromHelper] = await programClient.pdas.canonical({ program: programAddress, seed }); const manualPda = await deriveCanonicalPda(programAddress, seed); expect(pdaFromHelper).toBe(manualPda); }); test('should derive different PDAs for different seeds', async () => { const programAddress = await ctx.createAccount(); const [pda1] = await programClient.pdas.canonical({ program: programAddress, seed: 'idl' }); const [pda2] = await programClient.pdas.canonical({ program: programAddress, seed: 'config' }); expect(pda1).not.toBe(pda2); }); test('should derive different PDAs for different programs', async () => { const program1 = await ctx.createAccount(); const program2 = await ctx.createAccount(); const [pda1] = await programClient.pdas.canonical({ program: program1, seed: 'idl' }); const [pda2] = await programClient.pdas.canonical({ program: program2, seed: 'idl' }); expect(pda1).not.toBe(pda2); }); test('should match instruction-resolved metadata PDA', async () => { const seed = 'idl'; const { authority, programAddress, programDataAddress } = await setupCanonicalPda(ctx, seed); const ix = await programClient.methods .initialize({ compression: 'none', data: new TextEncoder().encode('test'), dataSource: 'direct', encoding: 'utf8', format: 'json', seed, }) .accounts({ authority, program: programAddress, programData: programDataAddress, }) .instruction(); const [pdaFromHelper] = await programClient.pdas.canonical({ program: programAddress, seed }); // The instruction's 1st account (index 0) is the metadata PDA const pdaFromIx = ix.accounts?.[0]?.address; expect(pdaFromHelper).toBe(pdaFromIx); }); }); describe('nonCanonical', () => { test('should derive non-canonical PDA matching manual derivation', async () => { const programAddress = await ctx.createAccount(); const authority = await ctx.createAccount(); const seed = 'idl'; const [pdaFromHelper] = await programClient.pdas.nonCanonical({ authority, program: programAddress, seed }); const manualPda = await deriveNonCanonicalPda(programAddress, authority, seed); expect(pdaFromHelper).toBe(manualPda); }); test('should derive different PDAs for different authorities', async () => { const programAddress = await ctx.createAccount(); const authority1 = await ctx.createAccount(); const authority2 = await ctx.createAccount(); const [pda1] = await programClient.pdas.nonCanonical({ authority: authority1, program: programAddress, seed: 'idl', }); const [pda2] = await programClient.pdas.nonCanonical({ authority: authority2, program: programAddress, seed: 'idl', }); expect(pda1).not.toBe(pda2); }); test('should match instruction-resolved metadata PDA', async () => { const seed = 'idl'; const { authority, programAddress } = await setupNonCanonicalPda(ctx, seed); const ix = await programClient.methods .initialize({ compression: 'none', data: new TextEncoder().encode('test'), dataSource: 'direct', encoding: 'utf8', format: 'json', seed, }) .accounts({ authority, program: programAddress, programData: null, }) .instruction(); const [pdaFromHelper] = await programClient.pdas.nonCanonical({ authority, program: programAddress, seed }); const pdaFromIx = ix.accounts?.[0]?.address; expect(pdaFromHelper).toBe(pdaFromIx); }); }); describe('metadata', () => { test('should derive canonical PDA when authority is null', async () => { const programAddress = await ctx.createAccount(); const seed = 'idl'; const [metadataPda] = await programClient.pdas.metadata({ authority: null, program: programAddress, seed }); const [canonicalPda] = await programClient.pdas.canonical({ program: programAddress, seed }); expect(metadataPda).toBe(canonicalPda); }); test('should derive non-canonical PDA when authority is provided', async () => { const programAddress = await ctx.createAccount(); const authority = await ctx.createAccount(); const seed = 'idl'; const [metadataPda] = await programClient.pdas.metadata({ authority, program: programAddress, seed }); const [nonCanonicalPda] = await programClient.pdas.nonCanonical({ authority, program: programAddress, seed, }); expect(metadataPda).toBe(nonCanonicalPda); }); }); }); ================================================ FILE: packages/dynamic-client/test/programs/pmp/set-authority.test.ts ================================================ import type { Address } from '@solana/addresses'; import type { Some } from '@solana/codecs'; import { beforeEach, describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { decodeMetadataAccount, initializeCanonicalMetadata, loadPmpProgram, programClient } from './helpers'; describe('Program Metadata: setAuthority', () => { let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext(); loadPmpProgram(ctx, programClient.programAddress); }); test('should set new authority on canonical metadata', async () => { const { authority, programAddress, programDataAddress, pda: metadataPda, } = await initializeCanonicalMetadata(ctx); const accountBefore = ctx.requireEncodedAccount(metadataPda); const metadataBefore = decodeMetadataAccount(accountBefore.data); expect(metadataBefore.authority).toEqual({ __option: 'None' }); expect(metadataBefore.canonical).toBe(true); // Set new authority const newAuthority = await ctx.createAccount(); const expectedAccounts = [metadataPda, authority, programAddress, programDataAddress]; const setAuthorityIx = await programClient.methods .setAuthority({ newAuthority }) .accounts({ account: metadataPda, authority, program: programAddress, programData: programDataAddress, }) .instruction(); expect(setAuthorityIx.accounts?.length).toBe(4); setAuthorityIx.accounts?.forEach((ixAccount, i) => { expect(expectedAccounts[i], `Invalid account: [${i}]`).toBe(ixAccount.address); }); await ctx.sendInstruction(setAuthorityIx, [authority]); const accountAfter = ctx.requireEncodedAccount(metadataPda); const metadataAfter = decodeMetadataAccount(accountAfter.data); expect((metadataAfter.authority as Some
).value).toBe(newAuthority); }); test('should remove authority from canonical metadata', async () => { const { authority, programAddress, programDataAddress, pda: metadataPda, } = await initializeCanonicalMetadata(ctx); // Set authority const someAuthority = await ctx.createAccount(); const setAuthorityIx = await programClient.methods .setAuthority({ newAuthority: someAuthority }) .accounts({ account: metadataPda, authority, program: programAddress, programData: programDataAddress, }) .instruction(); await ctx.sendInstruction(setAuthorityIx, [authority]); const accountWithAuthority = ctx.requireEncodedAccount(metadataPda); const metadataWithAuthority = decodeMetadataAccount(accountWithAuthority.data); expect((metadataWithAuthority.authority as Some
).value).toBe(someAuthority); // Remove the authority const expectedAccounts = [metadataPda, authority, programAddress, programDataAddress]; const removeAuthorityIx = await programClient.methods .setAuthority({ newAuthority: null }) .accounts({ account: metadataPda, authority, program: programAddress, programData: programDataAddress, }) .instruction(); expect(removeAuthorityIx.accounts?.length).toBe(4); removeAuthorityIx.accounts?.forEach((ixAccount, i) => { expect(expectedAccounts[i], `Invalid account: [${i}]`).toBe(ixAccount.address); }); await ctx.sendInstruction(removeAuthorityIx, [authority]); const accountAfter = ctx.requireEncodedAccount(metadataPda); const metadataAfter = decodeMetadataAccount(accountAfter.data); expect(metadataAfter.authority).toEqual({ __option: 'None' }); }); }); ================================================ FILE: packages/dynamic-client/test/programs/pmp/set-data.test.ts ================================================ import type { Address } from '@solana/addresses'; import type { Some } from '@solana/codecs'; import { Compression, DataSource, Encoding, Format } from '@solana-program/program-metadata'; import { beforeEach, describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { allocateBufferAccount, decodeMetadataAccount, initializeCanonicalMetadata, initializeNonCanonicalMetadata, loadPmpProgram, PMP_PROGRAM_ID, programClient, } from './helpers'; describe('Program Metadata: setData', () => { let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext(); loadPmpProgram(ctx, programClient.programAddress); }); test('should update canonical metadata with inline data', async () => { const { authority, programAddress, programDataAddress, pda: metadataPda, } = await initializeCanonicalMetadata(ctx, { data: new TextEncoder().encode('{"name":"initial"}') }); // Verify initial state const accountBefore = ctx.requireEncodedAccount(metadataPda); const metadataBefore = decodeMetadataAccount(accountBefore.data); expect(metadataBefore.encoding).toBe(Encoding.Utf8); expect(metadataBefore.format).toBe(Format.Json); // Update metadata with new data and properties const newData = new TextEncoder().encode('{"name":"updated"}'); const expectedAccounts = [metadataPda, authority, PMP_PROGRAM_ID, programAddress, programDataAddress]; const setDataIx = await programClient.methods .setData({ compression: 'zlib', data: newData, dataSource: 'direct', encoding: 'utf8', format: 'json', }) .accounts({ authority, buffer: null, metadata: metadataPda, program: programAddress, programData: programDataAddress, }) .instruction(); expect(setDataIx.accounts?.length).toBe(5); setDataIx.accounts?.forEach((ixAccount, i) => { expect(expectedAccounts[i], `Invalid account: [${i}]`).toBe(ixAccount.address); }); await ctx.sendInstruction(setDataIx, [authority]); // Verify metadata updated const accountAfter = ctx.requireEncodedAccount(metadataPda); const metadataAfter = decodeMetadataAccount(accountAfter.data); const writtenData = metadataAfter.data.slice(0, newData.length); expect(writtenData).toEqual(newData); expect(metadataAfter.encoding).toBe(Encoding.Utf8); expect(metadataAfter.compression).toBe(Compression.Zlib); expect(metadataAfter.format).toBe(Format.Json); expect(metadataAfter.dataSource).toBe(DataSource.Direct); // Unchanged fields expect(metadataAfter.canonical).toBe(true); expect(metadataAfter.program).toBe(programAddress); expect(metadataAfter.authority).toEqual({ __option: 'None' }); expect(metadataAfter.seed).toBe('idl'); expect(metadataAfter.mutable).toBe(true); }); test('should update canonical metadata from buffer', async () => { const feePayer = await ctx.createFundedAccount(); const { authority, programAddress, programDataAddress, pda: metadataPda, } = await initializeCanonicalMetadata(ctx, { data: new TextEncoder().encode('{"name":"initial"}') }); const { bufferAccount } = await allocateBufferAccount(ctx); const bufferData = new TextEncoder().encode('{"from":"buffer"}'); const writeBufferIx = await programClient.methods .write({ data: bufferData, offset: 0 }) .accounts({ authority: bufferAccount, buffer: bufferAccount, sourceBuffer: null, }) .instruction(); await ctx.sendInstruction(writeBufferIx, [feePayer, bufferAccount]); // Update metadata from buffer const expectedAccounts = [metadataPda, authority, bufferAccount, programAddress, programDataAddress]; const setDataIx = await programClient.methods .setData({ compression: 'none', data: null, dataSource: 'direct', encoding: 'utf8', format: 'json', }) .accounts({ authority, buffer: bufferAccount, metadata: metadataPda, program: programAddress, programData: programDataAddress, }) .instruction(); expect(setDataIx.accounts?.length).toBe(5); setDataIx.accounts?.forEach((ixAccount, i) => { expect(expectedAccounts[i], `Invalid account: [${i}]`).toBe(ixAccount.address); }); await ctx.sendInstruction(setDataIx, [authority]); // Verify metadata data matches buffer const accountAfter = ctx.requireEncodedAccount(metadataPda); const metadataAfter = decodeMetadataAccount(accountAfter.data); const writtenData = metadataAfter.data.slice(0, bufferData.length); expect(writtenData).toEqual(bufferData); }); test('should update non-canonical metadata with inline data', async () => { const { authority, programAddress, pda: metadataPda, } = await initializeNonCanonicalMetadata(ctx, { data: new TextEncoder().encode('non-canonical initial'), }); // Verify non-canonical const accountBefore = ctx.requireEncodedAccount(metadataPda); const metadataBefore = decodeMetadataAccount(accountBefore.data); expect(metadataBefore.canonical).toBe(false); expect((metadataBefore.authority as Some
).value).toBe(authority); // Update non-canonical metadata const newData = new TextEncoder().encode('non-canonical updated'); const expectedAccounts = [metadataPda, authority, PMP_PROGRAM_ID, programAddress, PMP_PROGRAM_ID]; const setDataIx = await programClient.methods .setData({ compression: 'gzip', data: newData, dataSource: 'direct', encoding: 'utf8', format: 'json', }) .accounts({ authority, buffer: null, metadata: metadataPda, program: programAddress, programData: null, }) .instruction(); expect(setDataIx.accounts?.length).toBe(5); setDataIx.accounts?.forEach((ixAccount, i) => { expect(expectedAccounts[i], `Invalid account: [${i}]`).toBe(ixAccount.address); }); await ctx.sendInstruction(setDataIx, [authority]); const accountAfter = ctx.requireEncodedAccount(metadataPda); const metadataAfter = decodeMetadataAccount(accountAfter.data); const writtenData = metadataAfter.data.slice(0, newData.length); expect(writtenData).toEqual(newData); expect(metadataAfter.encoding).toBe(Encoding.Utf8); expect(metadataAfter.compression).toBe(Compression.Gzip); expect(metadataAfter.format).toBe(Format.Json); expect(metadataAfter.dataSource).toBe(DataSource.Direct); expect((metadataAfter.authority as Some
).value).toBe(authority); }); }); ================================================ FILE: packages/dynamic-client/test/programs/pmp/set-immutable.test.ts ================================================ import type { Address } from '@solana/addresses'; import type { Some } from '@solana/codecs'; import { beforeEach, describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { decodeMetadataAccount, initializeCanonicalMetadata, initializeNonCanonicalMetadata, loadPmpProgram, PMP_PROGRAM_ID, programClient, } from './helpers'; describe('Program Metadata: setImmutable', () => { let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext(); loadPmpProgram(ctx, programClient.programAddress); }); test('should make canonical metadata immutable', async () => { const { authority, programAddress, programDataAddress, pda: metadataPda, } = await initializeCanonicalMetadata(ctx); const accountBefore = ctx.requireEncodedAccount(metadataPda); const metadataBefore = decodeMetadataAccount(accountBefore.data); expect(metadataBefore.mutable).toBe(true); expect(metadataBefore.canonical).toBe(true); // Make immutable const expectedAccounts = [metadataPda, authority, programAddress, programDataAddress]; const setImmutableIx = await programClient.methods .setImmutable() .accounts({ authority, metadata: metadataPda, program: programAddress, programData: programDataAddress, }) .instruction(); expect(setImmutableIx.accounts?.length).toBe(4); setImmutableIx.accounts?.forEach((ixAccount, i) => { expect(expectedAccounts[i], `Invalid account: [${i}]`).toBe(ixAccount.address); }); await ctx.sendInstruction(setImmutableIx, [authority]); const accountAfter = ctx.requireEncodedAccount(metadataPda); const metadataAfter = decodeMetadataAccount(accountAfter.data); expect(metadataAfter.mutable).toBe(false); }); test('should make non-canonical metadata immutable', async () => { const { authority, pda: metadataPda } = await initializeNonCanonicalMetadata(ctx); // Verify non-canonical and mutable const accountBefore = ctx.requireEncodedAccount(metadataPda); const metadataBefore = decodeMetadataAccount(accountBefore.data); expect(metadataBefore.canonical).toBe(false); expect(metadataBefore.mutable).toBe(true); expect((metadataBefore.authority as Some
).value).toBe(authority); // Make immutable const expectedAccounts = [metadataPda, authority, PMP_PROGRAM_ID, PMP_PROGRAM_ID]; const setImmutableIx = await programClient.methods .setImmutable() .accounts({ authority, metadata: metadataPda, program: null, programData: null, }) .instruction(); expect(setImmutableIx.accounts?.length).toBe(4); setImmutableIx.accounts?.forEach((ixAccount, i) => { expect(expectedAccounts[i], `Invalid account: [${i}]`).toBe(ixAccount.address); }); await ctx.sendInstruction(setImmutableIx, [authority]); const accountAfter = ctx.requireEncodedAccount(metadataPda); const metadataAfter = decodeMetadataAccount(accountAfter.data); expect(metadataAfter.mutable).toBe(false); expect(metadataAfter.canonical).toBe(false); expect((metadataAfter.authority as Some
).value).toBe(authority); }); }); ================================================ FILE: packages/dynamic-client/test/programs/pmp/trim.test.ts ================================================ import { beforeEach, describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { decodeMetadataAccount, initializeCanonicalMetadata, loadPmpProgram, programClient } from './helpers'; describe('Program Metadata: trim', () => { let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext({ defaultPrograms: true, sysvars: true }); loadPmpProgram(ctx, programClient.programAddress); }); test('should trim metadata to reduced size', async () => { const destination = await ctx.createAccount(); const { authority, programAddress, programDataAddress, pda: metadataPda, } = await initializeCanonicalMetadata(ctx, { data: new TextEncoder().encode('x'.repeat(200)) }); const reducedData = new TextEncoder().encode('x'.repeat(100)); const setDataIx = await programClient.methods .setData({ compression: 'none', data: reducedData, dataSource: 'direct', encoding: 'utf8', format: 'json', }) .accounts({ authority, buffer: null, metadata: metadataPda, program: programAddress, programData: programDataAddress, }) .instruction(); await ctx.sendInstruction(setDataIx, [authority]); const balanceBefore = ctx.getBalanceOrZero(destination); expect(balanceBefore).toBe(0n); const expectedAccounts = [ metadataPda, authority, programAddress, programDataAddress, destination, ctx.SYSVAR_RENT_ADDRESS, ]; const trimIx = await programClient.methods .trim() .accounts({ account: metadataPda, authority, destination, program: programAddress, programData: programDataAddress, }) .instruction(); expect(trimIx.accounts?.length).toBe(6); trimIx.accounts?.forEach((ixAccount, i) => { expect(expectedAccounts[i], `Invalid account: [${i}]`).toBe(ixAccount.address); }); await ctx.sendInstruction(trimIx, [authority]); const account = ctx.requireEncodedAccount(metadataPda); const metadata = decodeMetadataAccount(account.data); expect(metadata.data).toEqual(reducedData); const balanceAfter = ctx.getBalanceOrZero(destination); expect(balanceAfter).toBeGreaterThan(0n); }); }); ================================================ FILE: packages/dynamic-client/test/programs/pmp/write.test.ts ================================================ import { AccountDiscriminator } from '@solana-program/program-metadata'; import { beforeEach, describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { allocateBufferAccount, decodeBufferAccount, loadPmpProgram, programClient } from './helpers'; describe('Program Metadata: write', () => { let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext(); loadPmpProgram(ctx, programClient.programAddress); }); test('should write inline data to buffer', async () => { const feePayer = await ctx.createFundedAccount(); const { bufferAccount } = await allocateBufferAccount(ctx); const testData = new TextEncoder().encode('Hello, PMP!'); const writeIx = await programClient.methods .write({ data: testData, offset: 0 }) .accounts({ authority: bufferAccount, buffer: bufferAccount, sourceBuffer: null, }) .instruction(); await ctx.sendInstruction(writeIx, [feePayer, bufferAccount]); const account = ctx.requireEncodedAccount(bufferAccount); const buffer = decodeBufferAccount(account.data); expect(buffer.discriminator).toBe(AccountDiscriminator.Buffer); expect(buffer.canonical).toBe(false); const writtenData = buffer.data.slice(0, testData.length); expect(writtenData).toEqual(testData); }); test('should write data at offset', async () => { const feePayer = await ctx.createFundedAccount(); const { bufferAccount } = await allocateBufferAccount(ctx); const dataA = new TextEncoder().encode('AAAA'); const writeIxA = await programClient.methods .write({ data: dataA, offset: 0 }) .accounts({ authority: bufferAccount, buffer: bufferAccount, sourceBuffer: null, }) .instruction(); const dataB = new TextEncoder().encode('BBBB'); const dataBoffset = 10; const writeIxB = await programClient.methods .write({ data: dataB, offset: dataBoffset }) .accounts({ authority: bufferAccount, buffer: bufferAccount, sourceBuffer: null, }) .instruction(); await ctx.sendInstructions([writeIxA, writeIxB], [feePayer, bufferAccount]); const account = ctx.requireEncodedAccount(bufferAccount); const buffer = decodeBufferAccount(account.data); expect(buffer.discriminator).toBe(AccountDiscriminator.Buffer); const writtenDataA = buffer.data.slice(0, dataA.length); expect(writtenDataA).toEqual(dataA); const writtenDataB = buffer.data.slice(dataBoffset, dataBoffset + dataB.length); expect(writtenDataB).toEqual(dataB); const untouchedBytes = buffer.data.slice(dataA.length, dataBoffset); expect(untouchedBytes).toEqual(new Uint8Array([0, 0, 0, 0, 0, 0])); }); test('should write data in chunks', async () => { const feePayer = await ctx.createFundedAccount(); const { bufferAccount } = await allocateBufferAccount(ctx); const chunk1 = new TextEncoder().encode('Hello'); const writeIx1 = await programClient.methods .write({ data: chunk1, offset: 0 }) .accounts({ authority: bufferAccount, buffer: bufferAccount, sourceBuffer: null, }) .instruction(); const chunk2 = new TextEncoder().encode('World'); const chunk2Offset = chunk1.length; const writeIx2 = await programClient.methods .write({ data: chunk2, offset: chunk2Offset }) .accounts({ authority: bufferAccount, buffer: bufferAccount, sourceBuffer: null, }) .instruction(); await ctx.sendInstructions([writeIx1, writeIx2], [feePayer, bufferAccount]); const account = ctx.requireEncodedAccount(bufferAccount); const buffer = decodeBufferAccount(account.data); expect(buffer.discriminator).toBe(AccountDiscriminator.Buffer); const combinedData = buffer.data.slice(0, chunk1.length + chunk2.length); const expectedData = new TextEncoder().encode('HelloWorld'); expect(combinedData).toEqual(expectedData); const resultString = new TextDecoder().decode(combinedData); expect(resultString).toBe('HelloWorld'); }); }); ================================================ FILE: packages/dynamic-client/test/programs/sas/change-authorized-signers.test.ts ================================================ import { type Address } from '@solana/addresses'; import { getCredentialDecoder } from 'sas-lib'; import { beforeEach, describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createCredential, loadSasProgram, programClient } from './sas-test-utils'; describe('SAS: changeAuthorizedSigners', () => { let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext(); loadSasProgram(ctx); }); test('should replace authorized signers with a new set', async () => { const { authority, credentialPda } = await createCredential(ctx); const newSigner1 = await ctx.createAccount(); const newSigner2 = await ctx.createAccount(); const expectedAccounts = [authority, authority, credentialPda, ctx.SYSTEM_PROGRAM_ADDRESS]; const ix = await programClient.methods .changeAuthorizedSigners({ signers: [newSigner1, newSigner2] }) .accounts({ authority, credential: credentialPda, payer: authority }) .instruction(); expect(ix.accounts?.length).toBe(4); expectedAccounts.forEach((expected, i) => { expect(ix.accounts?.[i].address).eq(expected); }); await ctx.sendInstruction(ix, [authority]); const account = ctx.requireEncodedAccount(credentialPda); const credential = getCredentialDecoder().decode(account.data); expect(credential.authorizedSigners).toEqual([newSigner1, newSigner2]); }); test('should throw AccountError when credential is missing', async () => { const { authority } = await createCredential(ctx); await expect( programClient.methods .changeAuthorizedSigners({ signers: [authority] }) .accounts({ authority, credential: undefined as unknown as Address, payer: authority }) .instruction(), ).rejects.toThrow(/Missing account \[credential\]/); }); test('should throw ValidationError when signers arg is invalid', async () => { const { authority, credentialPda } = await createCredential(ctx); await expect( programClient.methods .changeAuthorizedSigners({ signers: { a: 42 } as unknown as Address[] }) .accounts({ authority, credential: credentialPda, payer: authority }) .instruction(), ).rejects.toThrow(/Invalid argument "signers"/); }); }); ================================================ FILE: packages/dynamic-client/test/programs/sas/change-schema-description.test.ts ================================================ import { type Address } from '@solana/addresses'; import { getSchemaDecoder } from 'sas-lib'; import { beforeEach, describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createCredential, createSchema, loadSasProgram, programClient } from './sas-test-utils'; describe('SAS: changeSchemaDescription', () => { let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext(); loadSasProgram(ctx); }); test('should update schema description', async () => { const { authority, credentialPda } = await createCredential(ctx); const { schemaPda } = await createSchema(ctx, authority, credentialPda); const expectedAccounts = [authority, authority, credentialPda, schemaPda, ctx.SYSTEM_PROGRAM_ADDRESS]; const ix = await programClient.methods .changeSchemaDescription({ description: 'Updated description' }) .accounts({ authority, credential: credentialPda, payer: authority, schema: schemaPda }) .instruction(); expect(ix.accounts?.length).toBe(5); expectedAccounts.forEach((expected, i) => { expect(ix.accounts?.[i].address).eq(expected); }); await ctx.sendInstruction(ix, [authority]); const account = ctx.requireEncodedAccount(schemaPda); const schema = getSchemaDecoder().decode(account.data); expect(schema.description).toEqual(new TextEncoder().encode('Updated description')); }); test('should throw AccountError when schema is missing', async () => { const { authority, credentialPda } = await createCredential(ctx); await expect( programClient.methods .changeSchemaDescription({ description: 'New description' }) .accounts({ authority, credential: credentialPda, payer: authority, schema: undefined as unknown as Address, }) .instruction(), ).rejects.toThrow(/Missing account \[schema\]/); }); test('should throw ValidationError when description is invalid', async () => { const { authority, credentialPda } = await createCredential(ctx); const { schemaPda } = await createSchema(ctx, authority, credentialPda); await expect( programClient.methods .changeSchemaDescription({ description: BigInt(42) as unknown as string }) .accounts({ authority, credential: credentialPda, payer: authority, schema: schemaPda, }) .instruction(), ).rejects.toThrow(/Invalid argument "description"/); }); }); ================================================ FILE: packages/dynamic-client/test/programs/sas/change-schema-status.test.ts ================================================ import { type Address } from '@solana/addresses'; import { getSchemaDecoder } from 'sas-lib'; import { beforeEach, describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createCredential, createSchema, loadSasProgram, programClient } from './sas-test-utils'; describe('SAS: changeSchemaStatus', () => { let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext(); loadSasProgram(ctx); }); test('should pause a schema', async () => { const { authority, credentialPda } = await createCredential(ctx); const { schemaPda } = await createSchema(ctx, authority, credentialPda); const expectedAccounts = [authority, credentialPda, schemaPda]; const ix = await programClient.methods .changeSchemaStatus({ isPaused: true }) .accounts({ authority, credential: credentialPda, schema: schemaPda }) .instruction(); expect(ix.accounts?.length).toBe(3); expectedAccounts.forEach((expected, i) => { expect(ix.accounts?.[i].address).eq(expected); }); await ctx.sendInstruction(ix, [authority]); const account = ctx.requireEncodedAccount(schemaPda); const schema = getSchemaDecoder().decode(account.data); expect(schema.isPaused).toBe(true); }); test('should unpause a schema', async () => { const { authority, credentialPda } = await createCredential(ctx); const { schemaPda } = await createSchema(ctx, authority, credentialPda); const pauseIx = await programClient.methods .changeSchemaStatus({ isPaused: true }) .accounts({ authority, credential: credentialPda, schema: schemaPda }) .instruction(); await ctx.sendInstruction(pauseIx, [authority]); const unpauseIx = await programClient.methods .changeSchemaStatus({ isPaused: false }) .accounts({ authority, credential: credentialPda, schema: schemaPda }) .instruction(); await ctx.sendInstruction(unpauseIx, [authority]); const account = ctx.requireEncodedAccount(schemaPda); const schema = getSchemaDecoder().decode(account.data); expect(schema.isPaused).toBe(false); }); test('should build correct instruction with 3 accounts', async () => { const { authority, credentialPda } = await createCredential(ctx); const { schemaPda } = await createSchema(ctx, authority, credentialPda); const ix = await programClient.methods .changeSchemaStatus({ isPaused: true }) .accounts({ authority, credential: credentialPda, schema: schemaPda }) .instruction(); expect(ix.accounts?.length).toBe(3); }); test('should throw AccountError when credential is missing', async () => { const { authority, credentialPda } = await createCredential(ctx); const { schemaPda } = await createSchema(ctx, authority, credentialPda); await expect( programClient.methods .changeSchemaStatus({ isPaused: true }) .accounts({ authority, credential: undefined as unknown as Address, schema: schemaPda }) .instruction(), ).rejects.toThrow(/Missing account \[credential\]/); }); test('should throw ArgumentError when isPaused is invalid', async () => { const { authority, credentialPda } = await createCredential(ctx); const { schemaPda } = await createSchema(ctx, authority, credentialPda); await expect( programClient.methods .changeSchemaStatus({ isPaused: 'yes' as unknown as boolean }) .accounts({ authority, credential: credentialPda, schema: schemaPda }) .instruction(), ).rejects.toThrow(/Invalid argument "isPaused"/); }); }); ================================================ FILE: packages/dynamic-client/test/programs/sas/change-schema-version.test.ts ================================================ import { type Address } from '@solana/addresses'; import { deriveSchemaPda, getSchemaDecoder } from 'sas-lib'; import { beforeEach, describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createCredential, createSchema, loadSasProgram, programClient, SCHEMA_DATA_STRING_TYPE, SCHEMA_DATA_U8_TYPE, } from './sas-test-utils'; describe('SAS: changeSchemaVersion', () => { let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext(); loadSasProgram(ctx); }); test('should create a new version of a schema', async () => { const { authority, credentialPda } = await createCredential(ctx); const { name, schemaPda: existingSchemaPda } = await createSchema(ctx, authority, credentialPda); const [newSchemaPda] = await deriveSchemaPda({ credential: credentialPda, name, version: 2 }); const expectedAccounts = [ authority, authority, credentialPda, existingSchemaPda, newSchemaPda, ctx.SYSTEM_PROGRAM_ADDRESS, ]; const ix = await programClient.methods .changeSchemaVersion({ fieldNames: ['fullName', 'age'], layout: new Uint8Array([SCHEMA_DATA_STRING_TYPE, SCHEMA_DATA_U8_TYPE]), }) .accounts({ authority, credential: credentialPda, existingSchema: existingSchemaPda, newSchema: newSchemaPda, payer: authority, }) .instruction(); expect(ix.accounts?.length).toBe(6); expectedAccounts.forEach((expected, i) => { expect(ix.accounts?.[i].address).eq(expected); }); await ctx.sendInstruction(ix, [authority]); const account = ctx.requireEncodedAccount(newSchemaPda); const schema = getSchemaDecoder().decode(account.data); expect(schema.layout).toEqual(new Uint8Array([SCHEMA_DATA_STRING_TYPE, SCHEMA_DATA_U8_TYPE])); expect(schema.version).toBe(2); }); test('should throw AccountError when existingSchema is missing', async () => { const { authority, credentialPda } = await createCredential(ctx); const { name, schemaPda: existingSchemaPda } = await createSchema(ctx, authority, credentialPda); const [newSchemaPda] = await deriveSchemaPda({ credential: credentialPda, name, version: 2 }); await expect( programClient.methods .changeSchemaVersion({ fieldNames: ['field123'], layout: new Uint8Array([12]) }) .accounts({ authority, credential: credentialPda, existingSchema: undefined as unknown as Address, newSchema: newSchemaPda, payer: authority, }) .instruction(), ).rejects.toThrow(/Missing account \[existingSchema\]/); await expect( programClient.methods .changeSchemaVersion({ fieldNames: ['field123'], layout: new Uint8Array([12]) }) .accounts({ authority, credential: credentialPda, existingSchema: existingSchemaPda, newSchema: undefined as unknown as Address, payer: authority, }) .instruction(), ).rejects.toThrow(/Missing account \[newSchema\]/); }); test('should throw ValidationError when argument is invalid', async () => { const { authority, credentialPda } = await createCredential(ctx); const { name, schemaPda: existingSchemaPda } = await createSchema(ctx, authority, credentialPda); const [newSchemaPda] = await deriveSchemaPda({ credential: credentialPda, name, version: 2 }); await expect( programClient.methods .changeSchemaVersion({ fieldNames: undefined as unknown as string[], layout: new Uint8Array([SCHEMA_DATA_STRING_TYPE, SCHEMA_DATA_U8_TYPE]), }) .accounts({ authority, credential: credentialPda, existingSchema: existingSchemaPda, newSchema: newSchemaPda, payer: authority, }) .instruction(), ).rejects.toThrow(/Invalid argument "fieldNames"/); await expect( programClient.methods .changeSchemaVersion({ fieldNames: ['test1', 'test2'], layout: 123 as unknown as Uint8Array, }) .accounts({ authority, credential: credentialPda, existingSchema: existingSchemaPda, newSchema: newSchemaPda, payer: authority, }) .instruction(), ).rejects.toThrow(/Invalid argument "layout"/); }); }); ================================================ FILE: packages/dynamic-client/test/programs/sas/close-attestation.test.ts ================================================ import { type Address } from '@solana/addresses'; import { deriveEventAuthorityAddress } from 'sas-lib'; import { beforeEach, describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createAttestation, createCredential, createSchema, loadSasProgram, programClient } from './sas-test-utils'; describe('SAS: closeAttestation', () => { let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext(); loadSasProgram(ctx); }); test('should close an attestation', async () => { const { authority, credentialPda } = await createCredential(ctx); const { schemaPda } = await createSchema(ctx, authority, credentialPda); const { attestationPda } = await createAttestation(ctx, authority, credentialPda, schemaPda); const eventAuthority = await deriveEventAuthorityAddress(); const expectedAccounts = [ authority, authority, credentialPda, attestationPda, eventAuthority, ctx.SYSTEM_PROGRAM_ADDRESS, programClient.programAddress, ]; const ix = await programClient.methods .closeAttestation() .accounts({ attestation: attestationPda, attestationProgram: programClient.programAddress, authority, credential: credentialPda, eventAuthority, payer: authority, }) .instruction(); expect(ix.accounts?.length).toBe(7); expectedAccounts.forEach((expected, i) => { expect(ix.accounts?.[i].address).eq(expected); }); await ctx.sendInstruction(ix, [authority]); const account = ctx.fetchEncodedAccount(attestationPda); expect(account).toBeNull(); }); test('should throw AccountError when required account is missing', async () => { const { authority, credentialPda } = await createCredential(ctx); const { schemaPda } = await createSchema(ctx, authority, credentialPda); const { attestationPda } = await createAttestation(ctx, authority, credentialPda, schemaPda); const eventAuthority = await deriveEventAuthorityAddress(); await expect( programClient.methods .closeAttestation() .accounts({ attestation: attestationPda, attestationProgram: programClient.programAddress, authority, credential: credentialPda, eventAuthority: undefined as unknown as Address, payer: authority, }) .instruction(), ).rejects.toThrow(/Missing account \[eventAuthority\]/); await expect( programClient.methods .closeAttestation() .accounts({ attestation: attestationPda, attestationProgram: programClient.programAddress, authority, credential: undefined as unknown as Address, eventAuthority: eventAuthority, payer: authority, }) .instruction(), ).rejects.toThrow(/Missing account \[credential\]/); await expect( programClient.methods .closeAttestation() .accounts({ attestation: attestationPda, attestationProgram: undefined as unknown as Address, authority, credential: credentialPda, eventAuthority: eventAuthority, payer: authority, }) .instruction(), ).rejects.toThrow(/Missing account \[attestationProgram\]/); }); }); ================================================ FILE: packages/dynamic-client/test/programs/sas/close-tokenized-attestation.test.ts ================================================ import { type Address } from '@solana/addresses'; import { findAssociatedTokenPda } from '@solana-program/token'; import { deriveAttestationMintPda, deriveAttestationPda, deriveEventAuthorityAddress, serializeAttestationData, } from 'sas-lib'; import { beforeEach, describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createCredential, createSchema, getAttestationMintSize, loadSasProgram, programClient, tokenizeSchema, } from './sas-test-utils'; const NFT_NAME = 'Test NFT'; const NFT_SYMBOL = 'TEST'; const NFT_URI = 'https://example.com/metadata.json'; async function createTokenizedAttestationSetup(ctx: SvmTestContext) { const { authority, credentialPda } = await createCredential(ctx); const { schemaPda, schema } = await createSchema(ctx, authority, credentialPda); const attestationData = serializeAttestationData(schema, { field1: 'test' }); const { sasPda, schemaMintPda } = await tokenizeSchema(ctx, authority, credentialPda, schemaPda); const nonce = await ctx.createAccount(); const recipient = await ctx.createFundedAccount(); const [attestationPda] = await deriveAttestationPda({ credential: credentialPda, nonce, schema: schemaPda }); const [attestationMintPda] = await deriveAttestationMintPda({ attestation: attestationPda }); const [recipientTokenAccount] = await findAssociatedTokenPda({ mint: attestationMintPda, owner: recipient, tokenProgram: ctx.TOKEN_2022_PROGRAM_ADDRESS, }); const mintAccountSpace = getAttestationMintSize({ attestationMint: attestationMintPda, attestationPda, name: NFT_NAME, sasPda, schemaMint: schemaMintPda, schemaPda, symbol: NFT_SYMBOL, uri: NFT_URI, }); const createIx = await programClient.methods .createTokenizedAttestation({ data: attestationData, expiry: 0n, mintAccountSpace, name: NFT_NAME, nonce, symbol: NFT_SYMBOL, uri: NFT_URI, }) .accounts({ associatedTokenProgram: ctx.ASSOCIATED_TOKEN_PROGRAM_ADDRESS, attestation: attestationPda, attestationMint: attestationMintPda, authority, credential: credentialPda, payer: authority, recipient, recipientTokenAccount, sasPda, schema: schemaPda, schemaMint: schemaMintPda, tokenProgram: ctx.TOKEN_2022_PROGRAM_ADDRESS, }) .instruction(); await ctx.sendInstruction(createIx, [authority]); return { attestationMintPda, attestationPda, authority, credentialPda, recipientTokenAccount, sasPda }; } describe('SAS: closeTokenizedAttestation', () => { let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext({ defaultPrograms: true }); loadSasProgram(ctx); }); test('should close a tokenized attestation', async () => { const { attestationMintPda, attestationPda, authority, credentialPda, recipientTokenAccount, sasPda } = await createTokenizedAttestationSetup(ctx); const eventAuthority = await deriveEventAuthorityAddress(); const expectedAccounts = [ authority, authority, credentialPda, attestationPda, eventAuthority, ctx.SYSTEM_PROGRAM_ADDRESS, programClient.programAddress, attestationMintPda, sasPda, recipientTokenAccount, ctx.TOKEN_2022_PROGRAM_ADDRESS, ]; const ix = await programClient.methods .closeTokenizedAttestation() .accounts({ attestation: attestationPda, attestationMint: attestationMintPda, attestationProgram: programClient.programAddress, attestationTokenAccount: recipientTokenAccount, authority, credential: credentialPda, eventAuthority, payer: authority, sasPda, tokenProgram: ctx.TOKEN_2022_PROGRAM_ADDRESS, }) .instruction(); expect(ix.accounts?.length).toBe(11); expectedAccounts.forEach((expected, i) => { expect(ix.accounts?.[i].address).eq(expected); }); await ctx.sendInstruction(ix, [authority]); const account = ctx.fetchEncodedAccount(attestationPda); expect(account).toBeNull(); }); test('should throw AccountError when required account is missing', async () => { const { attestationMintPda, attestationPda, authority, credentialPda, recipientTokenAccount, sasPda } = await createTokenizedAttestationSetup(ctx); const eventAuthority = await deriveEventAuthorityAddress(); await expect( programClient.methods .closeTokenizedAttestation() .accounts({ attestation: attestationPda, attestationMint: undefined as unknown as Address, attestationProgram: programClient.programAddress, attestationTokenAccount: recipientTokenAccount, authority, credential: credentialPda, eventAuthority, payer: authority, sasPda, tokenProgram: ctx.TOKEN_2022_PROGRAM_ADDRESS, }) .instruction(), ).rejects.toThrow(/Missing account \[attestationMint\]/); await expect( programClient.methods .closeTokenizedAttestation() .accounts({ attestation: attestationPda, attestationMint: attestationMintPda, attestationProgram: programClient.programAddress, attestationTokenAccount: undefined as unknown as Address, authority, credential: credentialPda, eventAuthority, payer: authority, sasPda, tokenProgram: ctx.TOKEN_2022_PROGRAM_ADDRESS, }) .instruction(), ).rejects.toThrow(/Missing account \[attestationTokenAccount\]/); }); }); ================================================ FILE: packages/dynamic-client/test/programs/sas/create-attestation.test.ts ================================================ import { type Address } from '@solana/addresses'; import { deriveAttestationPda, getAttestationDecoder, serializeAttestationData } from 'sas-lib'; import { beforeEach, describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createAttestation, createCredential, createSchema, loadSasProgram, programClient } from './sas-test-utils'; describe('SAS: createAttestation', () => { let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext(); loadSasProgram(ctx); }); test('should create an attestation with no expiry', async () => { const { authority, credentialPda } = await createCredential(ctx); const { schemaPda } = await createSchema(ctx, authority, credentialPda); const nonce = await ctx.createAccount(); const [attestationPda] = await deriveAttestationPda({ credential: credentialPda, nonce, schema: schemaPda }); const expectedAccounts = [ authority, authority, credentialPda, schemaPda, attestationPda, ctx.SYSTEM_PROGRAM_ADDRESS, ]; const ix = await programClient.methods .createAttestation({ data: new Uint8Array([0, 0, 0, 0]), expiry: 0, nonce }) .accounts({ attestation: attestationPda, authority, credential: credentialPda, payer: authority, schema: schemaPda, }) .instruction(); expect(ix.accounts?.length).toBe(6); expectedAccounts.forEach((expected, i) => { expect(ix.accounts?.[i].address).eq(expected); }); await ctx.sendInstruction(ix, [authority]); const account = ctx.requireEncodedAccount(attestationPda); const attestation = getAttestationDecoder().decode(account.data); expect(attestation.data).toEqual(new Uint8Array([0, 0, 0, 0])); expect(attestation.expiry).toBe(0n); }); test('should create an attestation with binary data', async () => { const { authority, credentialPda } = await createCredential(ctx); const { schemaPda, schema } = await createSchema(ctx, authority, credentialPda); const attestationData = serializeAttestationData(schema, { field1: 'test' }); const { attestationPda } = await createAttestation(ctx, authority, credentialPda, schemaPda, { data: attestationData, }); const account = ctx.requireEncodedAccount(attestationPda); const attestation = getAttestationDecoder().decode(account.data); expect(attestation.data).toEqual(new Uint8Array(attestationData)); expect(attestation.expiry).toBe(0n); }); test('should throw AccountError when attestation is missing', async () => { const { authority, credentialPda } = await createCredential(ctx); const { schemaPda } = await createSchema(ctx, authority, credentialPda); const nonce = await ctx.createAccount(); await expect( programClient.methods .createAttestation({ data: new Uint8Array([]), expiry: 0n, nonce }) .accounts({ attestation: undefined as unknown as Address, authority, credential: credentialPda, payer: authority, schema: schemaPda, }) .instruction(), ).rejects.toThrow(/Missing account \[attestation\]/); }); test('should throw ArgumentError when nonce is invalid', async () => { const { authority, credentialPda } = await createCredential(ctx); const { schemaPda } = await createSchema(ctx, authority, credentialPda); const nonce = await ctx.createAccount(); const [attestationPda] = await deriveAttestationPda({ credential: credentialPda, nonce, schema: schemaPda }); await expect( programClient.methods .createAttestation({ data: new Uint8Array([]), expiry: 0n, nonce: 'not-a-valid-address' as unknown as Address, }) .accounts({ attestation: attestationPda, authority, credential: credentialPda, payer: authority, schema: schemaPda, }) .instruction(), ).rejects.toThrow(/Invalid argument "nonce"/); }); }); ================================================ FILE: packages/dynamic-client/test/programs/sas/create-credential.test.ts ================================================ import { type Address } from '@solana/addresses'; import { deriveCredentialPda, getCredentialDecoder } from 'sas-lib'; import { beforeEach, describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { loadSasProgram, programClient } from './sas-test-utils'; describe('SAS: createCredential', () => { let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext(); loadSasProgram(ctx); }); test('should create a credential with multiple signers', async () => { const authority = await ctx.createFundedAccount(); const signer2 = await ctx.createAccount(); const signer3 = await ctx.createAccount(); const name = 'MultiSignerCredential'; const [credentialPda] = await deriveCredentialPda({ authority, name }); const expectedAccounts = [authority, credentialPda, authority, ctx.SYSTEM_PROGRAM_ADDRESS]; const ix = await programClient.methods .createCredential({ name, signers: [authority, signer2, signer3] }) .accounts({ authority, credential: credentialPda, payer: authority }) .instruction(); expect(ix.accounts?.length).toBe(4); expectedAccounts.forEach((expected, i) => { expect(ix.accounts?.[i].address).eq(expected); }); await ctx.sendInstruction(ix, [authority]); const account = ctx.requireEncodedAccount(credentialPda); const credential = getCredentialDecoder().decode(account.data); expect(credential).toMatchObject({ authority, authorizedSigners: [authority, signer2, signer3], name: new Uint8Array(Buffer.from(name)), }); }); test('should throw AccountError when credential is missing', async () => { const authority = await ctx.createFundedAccount(); await expect( programClient.methods .createCredential({ name: 'Test', signers: [authority] }) .accounts({ authority, credential: undefined as unknown as Address, payer: authority }) .instruction(), ).rejects.toThrow(/Missing account \[credential\]/); }); test('should throw ArgumentError when name is missing', async () => { const authority = await ctx.createFundedAccount(); const [credentialPda] = await deriveCredentialPda({ authority, name: 'dummy' }); await expect( programClient.methods .createCredential({ name: undefined as unknown as string, signers: [authority] }) .accounts({ authority, credential: credentialPda, payer: authority }) .instruction(), ).rejects.toThrow(/Invalid argument "name"/); }); }); ================================================ FILE: packages/dynamic-client/test/programs/sas/create-schema.test.ts ================================================ import { type Address } from '@solana/addresses'; import { getU32Encoder } from '@solana/codecs'; import { deriveSchemaPda, getSchemaDecoder } from 'sas-lib'; import { beforeEach, describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createCredential, loadSasProgram, programClient, SCHEMA_DATA_STRING_TYPE, SCHEMA_DATA_U8_TYPE, } from './sas-test-utils'; describe('SAS: createSchema', () => { let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext(); loadSasProgram(ctx); }); test('should create a schema', async () => { const { authority, credentialPda } = await createCredential(ctx); const name = 'FullNameSchema'; const [schemaPda] = await deriveSchemaPda({ credential: credentialPda, name, version: 1 }); const expectedAccounts = [authority, authority, credentialPda, schemaPda, ctx.SYSTEM_PROGRAM_ADDRESS]; const ix = await programClient.methods .createSchema({ description: 'This is description', fieldNames: ['firstName', 'age', 'lastName'], layout: new Uint8Array([SCHEMA_DATA_STRING_TYPE, SCHEMA_DATA_U8_TYPE, SCHEMA_DATA_STRING_TYPE]), name, }) .accounts({ authority, credential: credentialPda, payer: authority, schema: schemaPda }) .instruction(); expect(ix.accounts?.length).toBe(5); expectedAccounts.forEach((acc, idx) => { expect(ix.accounts?.[idx].address).toBe(acc); }); await ctx.sendInstruction(ix, [authority]); const textEncoder = new TextEncoder(); const account = ctx.requireEncodedAccount(schemaPda); const schema = getSchemaDecoder().decode(account.data); expect(schema.description).toEqual(textEncoder.encode('This is description')); const sizePrefixEncoder = getU32Encoder(); expect(schema.fieldNames).toEqual( new Uint8Array([ ...sizePrefixEncoder.encode('firstName'.length), ...textEncoder.encode('firstName'), ...sizePrefixEncoder.encode('age'.length), ...textEncoder.encode('age'), ...sizePrefixEncoder.encode('lastName'.length), ...textEncoder.encode('lastName'), ]), ); expect(schema.layout).toEqual( new Uint8Array([SCHEMA_DATA_STRING_TYPE, SCHEMA_DATA_U8_TYPE, SCHEMA_DATA_STRING_TYPE]), ); }); test('should throw AccountError when credential is missing', async () => { const authority = await ctx.createFundedAccount(); const [schemaPda] = await deriveSchemaPda({ credential: authority, name: 'dummy', version: 1 }); await expect( programClient.methods .createSchema({ description: '', fieldNames: ['field1'], layout: new Uint8Array([12]), name: 'Test' }) .accounts({ authority, credential: undefined as unknown as Address, payer: authority, schema: schemaPda, }) .instruction(), ).rejects.toThrow(/Missing account \[credential\]/); }); test('should throw AccountError when schema is missing', async () => { const { authority, credentialPda } = await createCredential(ctx); await expect( programClient.methods .createSchema({ description: '', fieldNames: ['field1'], layout: new Uint8Array([12]), name: 'Test' }) .accounts({ authority, credential: credentialPda, payer: authority, schema: undefined as unknown as Address, }) .instruction(), ).rejects.toThrow(/Missing account \[schema\]/); }); test('should throw ArgumentError when argument is invalid', async () => { const { authority, credentialPda } = await createCredential(ctx); const [schemaPda] = await deriveSchemaPda({ credential: credentialPda, name: 'dummy', version: 1 }); await expect( programClient.methods .createSchema({ description: '', fieldNames: ['field1'], layout: new Uint8Array([12]), name: undefined as unknown as string, }) .accounts({ authority, credential: credentialPda, payer: authority, schema: schemaPda }) .instruction(), ).rejects.toThrow(/Invalid argument "name"/); await expect( programClient.methods .createSchema({ description: '', fieldNames: { a: 42 } as unknown as string[], layout: new Uint8Array([12]), name: '234', }) .accounts({ authority, credential: credentialPda, payer: authority, schema: schemaPda }) .instruction(), ).rejects.toThrow(/Invalid argument "fieldNames"/); }); }); ================================================ FILE: packages/dynamic-client/test/programs/sas/create-tokenized-attestation.test.ts ================================================ import { type Address } from '@solana/addresses'; import { findAssociatedTokenPda } from '@solana-program/token'; import { deriveAttestationMintPda, deriveAttestationPda, getAttestationDecoder, serializeAttestationData, } from 'sas-lib'; import { beforeEach, describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createCredential, createSchema, getAttestationMintSize, loadSasProgram, programClient, tokenizeSchema, } from './sas-test-utils'; const NFT_NAME = 'Test NFT'; const NFT_SYMBOL = 'TEST'; const NFT_URI = 'https://example.com/metadata.json'; describe('SAS: createTokenizedAttestation', () => { let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext({ defaultPrograms: true }); loadSasProgram(ctx); }); test('should create a tokenized attestation', async () => { const { authority, credentialPda } = await createCredential(ctx); const { schemaPda, schema } = await createSchema(ctx, authority, credentialPda); const attestationData = serializeAttestationData(schema, { field1: 'test' }); const { sasPda, schemaMintPda } = await tokenizeSchema(ctx, authority, credentialPda, schemaPda); const nonce = await ctx.createAccount(); const recipient = await ctx.createFundedAccount(); const [attestationPda] = await deriveAttestationPda({ credential: credentialPda, nonce, schema: schemaPda }); const [attestationMintPda] = await deriveAttestationMintPda({ attestation: attestationPda }); const [recipientTokenAccount] = await findAssociatedTokenPda({ mint: attestationMintPda, owner: recipient, tokenProgram: ctx.TOKEN_2022_PROGRAM_ADDRESS, }); const mintAccountSpace = getAttestationMintSize({ attestationMint: attestationMintPda, attestationPda, name: NFT_NAME, sasPda, schemaMint: schemaMintPda, schemaPda, symbol: NFT_SYMBOL, uri: NFT_URI, }); const expectedAccounts = [ authority, authority, credentialPda, schemaPda, attestationPda, ctx.SYSTEM_PROGRAM_ADDRESS, schemaMintPda, attestationMintPda, sasPda, recipientTokenAccount, recipient, ctx.TOKEN_2022_PROGRAM_ADDRESS, ctx.ASSOCIATED_TOKEN_PROGRAM_ADDRESS, ]; const ix = await programClient.methods .createTokenizedAttestation({ data: attestationData, expiry: 0, mintAccountSpace, name: NFT_NAME, nonce, symbol: NFT_SYMBOL, uri: NFT_URI, }) .accounts({ associatedTokenProgram: ctx.ASSOCIATED_TOKEN_PROGRAM_ADDRESS, attestation: attestationPda, attestationMint: attestationMintPda, authority, credential: credentialPda, payer: authority, recipient, recipientTokenAccount, sasPda, schema: schemaPda, schemaMint: schemaMintPda, tokenProgram: ctx.TOKEN_2022_PROGRAM_ADDRESS, }) .instruction(); expect(ix.accounts?.length).toBe(13); expectedAccounts.forEach((expected, i) => { expect(ix.accounts?.[i].address).eq(expected); }); await ctx.sendInstruction(ix, [authority]); const account = ctx.requireEncodedAccount(attestationPda); const attestation = getAttestationDecoder().decode(account.data); expect(attestation).toMatchObject({ credential: credentialPda, data: new Uint8Array(attestationData), discriminator: 2, expiry: 0n, schema: schemaPda, }); }); test('should throw AccountError when schemaMint is missing', async () => { const { authority, credentialPda } = await createCredential(ctx); const { schemaPda } = await createSchema(ctx, authority, credentialPda); const { sasPda } = await tokenizeSchema(ctx, authority, credentialPda, schemaPda); const nonce = await ctx.createAccount(); const recipient = await ctx.createFundedAccount(); const [attestationPda] = await deriveAttestationPda({ credential: credentialPda, nonce, schema: schemaPda }); const [attestationMintPda] = await deriveAttestationMintPda({ attestation: attestationPda }); const [recipientTokenAccount] = await findAssociatedTokenPda({ mint: attestationMintPda, owner: recipient, tokenProgram: ctx.TOKEN_2022_PROGRAM_ADDRESS, }); await expect( programClient.methods .createTokenizedAttestation({ data: new Uint8Array([]), expiry: 0n, mintAccountSpace: 234, name: NFT_NAME, nonce, symbol: NFT_SYMBOL, uri: NFT_URI, }) .accounts({ associatedTokenProgram: ctx.ASSOCIATED_TOKEN_PROGRAM_ADDRESS, attestation: attestationPda, attestationMint: attestationMintPda, authority, credential: credentialPda, payer: authority, recipient, recipientTokenAccount, sasPda, schema: schemaPda, schemaMint: undefined as unknown as Address, tokenProgram: ctx.TOKEN_2022_PROGRAM_ADDRESS, }) .instruction(), ).rejects.toThrow(/Missing account \[schemaMint\]/); }); test('should throw error with invalid argument', async () => { const { authority, credentialPda } = await createCredential(ctx); const { schemaPda } = await createSchema(ctx, authority, credentialPda); const { sasPda } = await tokenizeSchema(ctx, authority, credentialPda, schemaPda); const nonce = await ctx.createAccount(); const recipient = await ctx.createFundedAccount(); const [attestationPda] = await deriveAttestationPda({ credential: credentialPda, nonce, schema: schemaPda }); const [attestationMintPda] = await deriveAttestationMintPda({ attestation: attestationPda }); const [recipientTokenAccount] = await findAssociatedTokenPda({ mint: attestationMintPda, owner: recipient, tokenProgram: ctx.TOKEN_2022_PROGRAM_ADDRESS, }); await expect( programClient.methods .createTokenizedAttestation({ data: { a: 42 } as unknown as Uint8Array, expiry: 0n, mintAccountSpace: 234, name: NFT_NAME, nonce, symbol: NFT_SYMBOL, uri: NFT_URI, }) .accounts({ associatedTokenProgram: ctx.ASSOCIATED_TOKEN_PROGRAM_ADDRESS, attestation: attestationPda, attestationMint: attestationMintPda, authority, credential: credentialPda, payer: authority, recipient, recipientTokenAccount, sasPda, schema: schemaPda, schemaMint: undefined as unknown as Address, tokenProgram: ctx.TOKEN_2022_PROGRAM_ADDRESS, }) .instruction(), ).rejects.toThrow(/Invalid argument "data"/); }); }); ================================================ FILE: packages/dynamic-client/test/programs/sas/sas-test-utils.ts ================================================ import path from 'node:path'; import { type Address } from '@solana/addresses'; import { getMintSize } from '@solana-program/token-2022'; import { deriveAttestationPda, deriveCredentialPda, deriveSasAuthorityAddress, deriveSchemaMintPda, deriveSchemaPda, getSchemaDecoder, } from 'sas-lib'; import type { SvmTestContext } from '../../svm-test-context'; import type { SolanaAttestationServiceProgramClient } from '../generated/sas-idl-types'; import { createTestProgramClient } from '../test-utils'; export const programClient = createTestProgramClient('sas-idl.json'); export function loadSasProgram(ctx: SvmTestContext) { const programPath = path.resolve(__dirname, '..', 'dumps', 'sas.so'); ctx.loadProgram(programClient.programAddress, programPath); } /** * Compute the mint account space needed for TokenizedSchema. */ export function getSchemaMintSize(sasPda: Address, schemaMint: Address) { return getMintSize([{ __kind: 'GroupPointer', authority: sasPda, groupAddress: schemaMint }]); } /** * Compute the mint account space needed for TokenizedAttestation. */ export function getAttestationMintSize({ sasPda, attestationMint, schemaMint, name, symbol, uri, attestationPda, schemaPda, }: { attestationMint: Address; attestationPda: Address; name: string; sasPda: Address; schemaMint: Address; schemaPda: Address; symbol: string; uri: string; }) { return getMintSize([ { __kind: 'GroupMemberPointer', authority: sasPda, memberAddress: attestationMint }, { __kind: 'NonTransferable' }, { __kind: 'MetadataPointer', authority: sasPda, metadataAddress: attestationMint }, { __kind: 'PermanentDelegate', delegate: sasPda }, { __kind: 'MintCloseAuthority', closeAuthority: sasPda }, { __kind: 'TokenMetadata', additionalMetadata: new Map([ ['attestation', attestationPda], ['schema', schemaPda], ]), mint: attestationMint, name, symbol, updateAuthority: sasPda, uri, }, { __kind: 'TokenGroupMember', group: schemaMint, memberNumber: 1, mint: attestationMint }, ]); } export async function createCredential(ctx: SvmTestContext, opts?: { name?: string; signers?: Address[] }) { const authority = await ctx.createFundedAccount(); const name = opts?.name ?? 'TestCredential'; const signers = opts?.signers ?? [authority]; const [credentialPda] = await deriveCredentialPda({ authority, name }); const ix = await programClient.methods .createCredential({ name, signers }) .accounts({ authority, credential: credentialPda, payer: authority }) .instruction(); await ctx.sendInstruction(ix, [authority]); return { authority, credentialPda, name }; } // https://github.com/solana-foundation/solana-attestation-service/blob/master/program/src/state/schema.rs#L26 export const SCHEMA_DATA_STRING_TYPE = 12; export const SCHEMA_DATA_U8_TYPE = 0; /** * Helper function to create a schema. * - Derives the schema PDA * - Sends the createSchema instruction * - Fetches and decodes the created schema account */ export async function createSchema( ctx: SvmTestContext, authority: Address, credentialPda: Address, opts?: { description?: string; fieldNames?: string[]; layout?: Uint8Array; name?: string; version?: number }, ) { const description = opts?.description ?? ''; const fieldNames = opts?.fieldNames ?? ['field1']; const layout = opts?.layout ?? new Uint8Array([SCHEMA_DATA_STRING_TYPE]); const name = opts?.name ?? 'TestSchema'; const version = opts?.version ?? 1; const [schemaPda] = await deriveSchemaPda({ credential: credentialPda, name, version }); const ix = await programClient.methods .createSchema({ description, fieldNames, layout, name }) .accounts({ authority, credential: credentialPda, payer: authority, schema: schemaPda }) .instruction(); await ctx.sendInstruction(ix, [authority]); const schemaData = ctx.requireEncodedAccount(schemaPda).data; const schema = getSchemaDecoder().decode(schemaData); return { name, schema, schemaData, schemaPda, version }; } export async function createAttestation( ctx: SvmTestContext, authority: Address, credentialPda: Address, schemaPda: Address, opts?: { data?: Uint8Array; expiry?: bigint }, ) { const data = opts?.data ?? new Uint8Array([0, 0, 0, 0]); const expiry = opts?.expiry ?? 0n; const nonce = await ctx.createAccount(); const [attestationPda] = await deriveAttestationPda({ credential: credentialPda, nonce, schema: schemaPda }); const ix = await programClient.methods .createAttestation({ data, expiry, nonce }) .accounts({ attestation: attestationPda, authority, credential: credentialPda, payer: authority, schema: schemaPda, }) .instruction(); await ctx.sendInstruction(ix, [authority]); return { attestationPda, nonce }; } export async function tokenizeSchema( ctx: SvmTestContext, authority: Address, credentialPda: Address, schemaPda: Address, ) { const sasPda = await deriveSasAuthorityAddress(); const [schemaMintPda] = await deriveSchemaMintPda({ schema: schemaPda }); const maxSize = BigInt(getSchemaMintSize(sasPda, schemaMintPda)); const ix = await programClient.methods .tokenizeSchema({ maxSize }) .accounts({ authority, credential: credentialPda, mint: schemaMintPda, payer: authority, sasPda, schema: schemaPda, tokenProgram: ctx.TOKEN_2022_PROGRAM_ADDRESS, }) .instruction(); await ctx.sendInstruction(ix, [authority]); return { sasPda, schemaMintPda }; } ================================================ FILE: packages/dynamic-client/test/programs/sas/tokenize-schema.test.ts ================================================ import { type Address } from '@solana/addresses'; import { deriveSasAuthorityAddress, deriveSchemaMintPda } from 'sas-lib'; import { beforeEach, describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createCredential, createSchema, getSchemaMintSize, loadSasProgram, programClient } from './sas-test-utils'; describe('SAS: tokenizeSchema', () => { let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext({ defaultPrograms: true }); loadSasProgram(ctx); }); test('should tokenize a schema and create a mint', async () => { const { authority, credentialPda } = await createCredential(ctx); const { schemaPda } = await createSchema(ctx, authority, credentialPda); const sasPda = await deriveSasAuthorityAddress(); const [schemaMintPda] = await deriveSchemaMintPda({ schema: schemaPda }); const maxSize = BigInt(getSchemaMintSize(sasPda, schemaMintPda)); const expectedAccounts = [ authority, authority, credentialPda, schemaPda, schemaMintPda, sasPda, ctx.SYSTEM_PROGRAM_ADDRESS, ctx.TOKEN_2022_PROGRAM_ADDRESS, ]; const ix = await programClient.methods .tokenizeSchema({ maxSize }) .accounts({ authority, credential: credentialPda, mint: schemaMintPda, payer: authority, sasPda, schema: schemaPda, tokenProgram: ctx.TOKEN_2022_PROGRAM_ADDRESS, }) .instruction(); expect(ix.accounts?.length).toBe(8); expectedAccounts.forEach((expected, i) => { if (!ix?.accounts?.[i]) { throw new Error(`Expected instruction accounts to be defined at index ${i}`); } expect(ix.accounts[i].address).eq(expected); }); await ctx.sendInstruction(ix, [authority]); const account = ctx.requireEncodedAccount(schemaMintPda); expect(account).not.toBeNull(); expect(account.data.length).greaterThan(0); }); test('should throw AccountError when mint is missing', async () => { const { authority, credentialPda } = await createCredential(ctx); const { schemaPda } = await createSchema(ctx, authority, credentialPda); const sasPda = await deriveSasAuthorityAddress(); const [schemaMintPda] = await deriveSchemaMintPda({ schema: schemaPda }); const maxSize = getSchemaMintSize(sasPda, schemaMintPda); // should work as number await expect( programClient.methods .tokenizeSchema({ maxSize }) .accounts({ authority, credential: credentialPda, mint: undefined as unknown as Address, payer: authority, sasPda, schema: schemaPda, tokenProgram: ctx.TOKEN_2022_PROGRAM_ADDRESS, }) .instruction(), ).rejects.toThrow(/Missing account \[mint\]/); }); test('should throw AccountError when maxSize arg is missing', async () => { const { authority, credentialPda } = await createCredential(ctx); const { schemaPda } = await createSchema(ctx, authority, credentialPda); const sasPda = await deriveSasAuthorityAddress(); const [schemaMintPda] = await deriveSchemaMintPda({ schema: schemaPda }); await expect( programClient.methods .tokenizeSchema({ maxSize: 'jondoe' as unknown as bigint }) .accounts({ authority, credential: credentialPda, mint: schemaMintPda, payer: authority, sasPda, schema: schemaPda, tokenProgram: ctx.TOKEN_2022_PROGRAM_ADDRESS, }) .instruction(), ).rejects.toThrow(/Invalid argument "maxSize"/); }); }); ================================================ FILE: packages/dynamic-client/test/programs/system-program/advance-nonce-account.test.ts ================================================ import { beforeEach, describe, expect, test } from 'vitest'; import type { SystemProgramClient } from '../generated/system-program-idl-types'; import { createTestProgramClient, SvmTestContext } from '../test-utils'; describe('System Program: advanceNonceAccount', () => { const programClient = createTestProgramClient('system-program-idl.json'); let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext(); }); test('should advance nonce multiple times and work after authority change', async () => { const payer = await ctx.createFundedAccount(); const nonceAccount = await ctx.createAccount(); const originalAuthority = await ctx.createFundedAccount(); const newAuthority = await ctx.createFundedAccount(); const nonceAccountSpace = 80; const fundingLamports = 10_000_000; const createAccountInstruction = await programClient.methods .createAccount({ lamports: fundingLamports, programAddress: programClient.programAddress, space: nonceAccountSpace, }) .accounts({ newAccount: nonceAccount, payer, }) .instruction(); await ctx.sendInstruction(createAccountInstruction, [payer, nonceAccount]); const initializeNonceInstruction = await programClient.methods .initializeNonceAccount({ nonceAuthority: originalAuthority, }) .accounts({ nonceAccount, }) .instruction(); await ctx.sendInstruction(initializeNonceInstruction, [payer]); const initialData = ctx.requireEncodedAccount(nonceAccount).data; ctx.advanceSlots(); const advanceNonceInstruction1 = await programClient.methods .advanceNonceAccount() .accounts({ nonceAccount, nonceAuthority: originalAuthority, }) .instruction(); await ctx.sendInstruction(advanceNonceInstruction1, [originalAuthority]); const dataAfterFirstAdvance = ctx.requireEncodedAccount(nonceAccount).data; expect(dataAfterFirstAdvance).not.toEqual(initialData); ctx.advanceSlots(); const advanceNonceInstruction2 = await programClient.methods .advanceNonceAccount() .accounts({ nonceAccount, nonceAuthority: originalAuthority, }) .instruction(); await ctx.sendInstruction(advanceNonceInstruction2, [originalAuthority]); const dataAfterSecondAdvance = ctx.requireEncodedAccount(nonceAccount).data; expect(dataAfterSecondAdvance).not.toEqual(dataAfterFirstAdvance); const authorizeNonceInstruction = await programClient.methods .authorizeNonceAccount({ newNonceAuthority: newAuthority, }) .accounts({ nonceAccount, nonceAuthority: originalAuthority, }) .instruction(); await ctx.sendInstruction(authorizeNonceInstruction, [originalAuthority]); ctx.advanceSlots(); const advanceWithNewAuthority = await programClient.methods .advanceNonceAccount() .accounts({ nonceAccount, nonceAuthority: newAuthority, }) .instruction(); await ctx.sendInstruction(advanceWithNewAuthority, [newAuthority]); const finalAccount = ctx.requireEncodedAccount(nonceAccount); expect(finalAccount).toMatchObject({ executable: false, lamports: BigInt(fundingLamports), owner: programClient.programAddress, }); expect(finalAccount.data.length).toBe(nonceAccountSpace); }); }); ================================================ FILE: packages/dynamic-client/test/programs/system-program/allocate-with-seed.test.ts ================================================ import { beforeEach, describe, expect, test } from 'vitest'; import type { SystemProgramClient } from '../generated/system-program-idl-types'; import { createTestProgramClient, SvmTestContext } from '../test-utils'; describe('System Program: allocateWithSeed', () => { const programClient = createTestProgramClient('system-program-idl.json'); let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext(); }); test('should allocate space for a seed-derived account', async () => { const payerAccount = await ctx.createFundedAccount(); const baseAccount = await ctx.createFundedAccount(); const seed = 'storage'; const newAccount = await ctx.createAccountWithSeed(baseAccount, seed, programClient.programAddress); const fundingLamports = 5_000_000; const createIx = await programClient.methods .createAccountWithSeed({ amount: fundingLamports, base: baseAccount, programAddress: programClient.programAddress, seed, space: 0, }) .accounts({ baseAccount, newAccount, payer: payerAccount, }) .instruction(); await ctx.sendInstruction(createIx, [payerAccount, baseAccount]); const space = 96; const allocateIx = await programClient.methods .allocateWithSeed({ base: baseAccount, programAddress: programClient.programAddress, seed, space, }) .accounts({ baseAccount, newAccount, }) .instruction(); await ctx.sendInstruction(allocateIx, [baseAccount]); const accountAfter = ctx.requireEncodedAccount(newAccount); expect(accountAfter).toMatchObject({ data: new Uint8Array(space), owner: programClient.programAddress, }); }); }); ================================================ FILE: packages/dynamic-client/test/programs/system-program/allocate.test.ts ================================================ import { beforeEach, describe, expect, test } from 'vitest'; import type { SystemProgramClient } from '../generated/system-program-idl-types'; import { createTestProgramClient, SvmTestContext } from '../test-utils'; describe('System Program: allocate', () => { const programClient = createTestProgramClient('system-program-idl.json'); let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext(); }); test('should allocate space for an account', async () => { const account = await ctx.createFundedAccount(); const space = 100; const accountBefore = ctx.requireEncodedAccount(account); expect(accountBefore.data.length).toBe(0); const instruction = await programClient.methods .allocate({ space }) .accounts({ newAccount: account }) .instruction(); await ctx.sendInstruction(instruction, [account]); const accountAfter = ctx.requireEncodedAccount(account); expect(accountAfter).toMatchObject({ owner: programClient.programAddress, }); expect(accountAfter.data.length).toBe(space); expect(accountAfter.lamports).toBeLessThan(accountBefore.lamports); expect(accountAfter.data.every(byte => byte === 0)).toBe(true); }); }); ================================================ FILE: packages/dynamic-client/test/programs/system-program/assign-with-seed.test.ts ================================================ import { beforeEach, describe, expect, test } from 'vitest'; import type { SystemProgramClient } from '../generated/system-program-idl-types'; import { createTestProgramClient, SvmTestContext } from '../test-utils'; describe('System Program: assignWithSeed', () => { const programClient = createTestProgramClient('system-program-idl.json'); let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext(); }); test('should assign seed-derived account to system program', async () => { const payerAccount = await ctx.createFundedAccount(); const baseAccount = await ctx.createFundedAccount(); const seed = 'wallet'; const account = await ctx.createAccountWithSeed(baseAccount, seed, programClient.programAddress); const createIx = await programClient.methods .createAccountWithSeed({ amount: 5_000_000, base: baseAccount, programAddress: programClient.programAddress, seed, space: 32, }) .accounts({ baseAccount, newAccount: account, payer: payerAccount, }) .instruction(); await ctx.sendInstruction(createIx, [payerAccount, baseAccount]); const assignIx = await programClient.methods .assignWithSeed({ base: baseAccount, programAddress: programClient.programAddress, seed, }) .accounts({ account, baseAccount, }) .instruction(); await ctx.sendInstruction(assignIx, [baseAccount]); expect(ctx.requireEncodedAccount(account)).toMatchObject({ owner: programClient.programAddress, }); }); }); ================================================ FILE: packages/dynamic-client/test/programs/system-program/assign.test.ts ================================================ import { beforeEach, describe, expect, test } from 'vitest'; import type { SystemProgramClient } from '../generated/system-program-idl-types'; import { createTestProgramClient, SvmTestContext } from '../test-utils'; describe('System Program: assign', () => { const programClient = createTestProgramClient('system-program-idl.json'); let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext(); }); test('should assign a new owner to an account', async () => { const payer = await ctx.createFundedAccount(); const accountToAssign = await ctx.createAccount(); const newOwner = await ctx.createAccount(); const amount = 1_000_000; const transferInstruction = await programClient.methods .transferSol({ amount }) .accounts({ destination: accountToAssign, source: payer, }) .instruction(); const assignInstruction = await programClient.methods .assign({ programAddress: newOwner }) .accounts({ account: accountToAssign }) .instruction(); await ctx.sendInstructions([transferInstruction, assignInstruction], [payer, accountToAssign]); expect(ctx.requireEncodedAccount(accountToAssign)).toMatchObject({ lamports: BigInt(amount), owner: newOwner, }); }); test('should assign account to system program', async () => { const account = await ctx.createFundedAccount(); const instruction = await programClient.methods .assign({ programAddress: programClient.programAddress }) .accounts({ account: account }) .instruction(); await ctx.sendInstruction(instruction, [account]); const encodedAccount = ctx.requireEncodedAccount(account); expect(encodedAccount).toMatchObject({ owner: programClient.programAddress, }); }); }); ================================================ FILE: packages/dynamic-client/test/programs/system-program/authorize-nonce-account.test.ts ================================================ import { beforeEach, describe, expect, test } from 'vitest'; import type { SystemProgramClient } from '../generated/system-program-idl-types'; import { createTestProgramClient, SvmTestContext } from '../test-utils'; describe('System Program: authorizeNonceAccount', () => { const programClient = createTestProgramClient('system-program-idl.json'); let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext(); }); test('should change nonce account authority to a new authority', async () => { const payer = await ctx.createFundedAccount(); const nonceAccount = await ctx.createAccount(); const originalAuthority = await ctx.createFundedAccount(); const newAuthority = await ctx.createAccount(); const nonceAccountSpace = 80; const fundingLamports = 10_000_000; const createAccountInstruction = await programClient.methods .createAccount({ lamports: fundingLamports, programAddress: programClient.programAddress, space: nonceAccountSpace, }) .accounts({ newAccount: nonceAccount, payer, }) .instruction(); await ctx.sendInstruction(createAccountInstruction, [payer, nonceAccount]); const initializeNonceInstruction = await programClient.methods .initializeNonceAccount({ nonceAuthority: originalAuthority, }) .accounts({ nonceAccount, }) .instruction(); await ctx.sendInstruction(initializeNonceInstruction, [payer]); const initializedAccount = ctx.requireEncodedAccount(nonceAccount); expect(initializedAccount).toMatchObject({ executable: false, lamports: BigInt(fundingLamports), owner: programClient.programAddress, }); const authorizeNonceInstruction = await programClient.methods .authorizeNonceAccount({ newNonceAuthority: newAuthority, }) .accounts({ nonceAccount, nonceAuthority: originalAuthority, }) .instruction(); await ctx.sendInstruction(authorizeNonceInstruction, [originalAuthority]); const authorizedAccount = ctx.requireEncodedAccount(nonceAccount); expect(authorizedAccount).toMatchObject({ executable: false, lamports: BigInt(fundingLamports), owner: programClient.programAddress, }); expect(authorizedAccount.data.length).toBe(nonceAccountSpace); }); test('should allow changing authority multiple times', async () => { const payer = await ctx.createFundedAccount(); const nonceAccount = await ctx.createAccount(); const firstAuthority = await ctx.createFundedAccount(); const secondAuthority = await ctx.createFundedAccount(); const thirdAuthority = await ctx.createAccount(); const nonceAccountSpace = 80; const fundingLamports = 10_000_000; const createAccountInstruction = await programClient.methods .createAccount({ lamports: fundingLamports, programAddress: programClient.programAddress, space: nonceAccountSpace, }) .accounts({ newAccount: nonceAccount, payer, }) .instruction(); await ctx.sendInstruction(createAccountInstruction, [payer, nonceAccount]); const initializeNonceInstruction = await programClient.methods .initializeNonceAccount({ nonceAuthority: firstAuthority, }) .accounts({ nonceAccount, }) .instruction(); await ctx.sendInstruction(initializeNonceInstruction, [payer]); const authorizeToSecondInstruction = await programClient.methods .authorizeNonceAccount({ newNonceAuthority: secondAuthority, }) .accounts({ nonceAccount, nonceAuthority: firstAuthority, }) .instruction(); await ctx.sendInstruction(authorizeToSecondInstruction, [firstAuthority]); const authorizeToThirdInstruction = await programClient.methods .authorizeNonceAccount({ newNonceAuthority: thirdAuthority, }) .accounts({ nonceAccount, nonceAuthority: secondAuthority, }) .instruction(); await ctx.sendInstruction(authorizeToThirdInstruction, [secondAuthority]); const finalAccount = ctx.requireEncodedAccount(nonceAccount); expect(finalAccount).toMatchObject({ executable: false, lamports: BigInt(fundingLamports), owner: programClient.programAddress, }); expect(finalAccount.data.length).toBe(nonceAccountSpace); }); test('should work when authority transfers to itself (no-op transfer)', async () => { const payer = await ctx.createFundedAccount(); const nonceAccount = await ctx.createAccount(); const authority = await ctx.createFundedAccount(); const nonceAccountSpace = 80; const fundingLamports = 10_000_000; const createAccountInstruction = await programClient.methods .createAccount({ lamports: fundingLamports, programAddress: programClient.programAddress, space: nonceAccountSpace, }) .accounts({ newAccount: nonceAccount, payer, }) .instruction(); await ctx.sendInstruction(createAccountInstruction, [payer, nonceAccount]); const initializeNonceInstruction = await programClient.methods .initializeNonceAccount({ nonceAuthority: authority, }) .accounts({ nonceAccount, }) .instruction(); await ctx.sendInstruction(initializeNonceInstruction, [payer]); const authorizeInstruction = await programClient.methods .authorizeNonceAccount({ newNonceAuthority: authority, }) .accounts({ nonceAccount, nonceAuthority: authority, }) .instruction(); await ctx.sendInstruction(authorizeInstruction, [authority]); const finalAccount = ctx.requireEncodedAccount(nonceAccount); expect(finalAccount).toMatchObject({ executable: false, lamports: BigInt(fundingLamports), owner: programClient.programAddress, }); }); }); ================================================ FILE: packages/dynamic-client/test/programs/system-program/create-account-with-seed.test.ts ================================================ import { beforeEach, describe, expect, test } from 'vitest'; import type { SystemProgramClient } from '../generated/system-program-idl-types'; import { createTestProgramClient, SvmTestContext } from '../test-utils'; describe('System Program: createAccountWithSeed', () => { const programClient = createTestProgramClient('system-program-idl.json'); let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext(); }); test('should create a new account at a seed-derived address', async () => { const payerAccount = await ctx.createFundedAccount(); const baseAccount = await ctx.createFundedAccount(); const seed = 'vault'; const newAccount = await ctx.createAccountWithSeed(baseAccount, seed, programClient.programAddress); const accountSpace = 64; const fundingLamports = 5_000_000; const createAccountWithSeedInstruction = await programClient.methods .createAccountWithSeed({ amount: fundingLamports, base: baseAccount, programAddress: programClient.programAddress, seed, space: accountSpace, }) .accounts({ baseAccount, newAccount, payer: payerAccount, }) .instruction(); await ctx.sendInstruction(createAccountWithSeedInstruction, [payerAccount, baseAccount]); const createdAccount = ctx.requireEncodedAccount(newAccount); expect(createdAccount).toMatchObject({ data: new Uint8Array(accountSpace), executable: false, lamports: BigInt(fundingLamports), owner: programClient.programAddress, }); }); }); ================================================ FILE: packages/dynamic-client/test/programs/system-program/create-account.test.ts ================================================ import { beforeEach, describe, expect, test } from 'vitest'; import type { SystemProgramClient } from '../generated/system-program-idl-types'; import { createTestProgramClient, SvmTestContext } from '../test-utils'; describe('System Program: createAccount', () => { const programClient = createTestProgramClient('system-program-idl.json'); let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext(); }); test('should create a new account with specified space and lamports', async () => { const payerAccount = await ctx.createFundedAccount(); const newAccountAddress = await ctx.createAccount(); const accountSpace = 165; const fundingLamports = 10_000_000; const createAccountInstruction = await programClient.methods .createAccount({ lamports: fundingLamports, programAddress: programClient.programAddress, space: accountSpace, }) .accounts({ newAccount: newAccountAddress, payer: payerAccount, }) .instruction(); await ctx.sendInstruction(createAccountInstruction, [payerAccount, newAccountAddress]); const createdAccount = ctx.requireEncodedAccount(newAccountAddress); expect(createdAccount).toMatchObject({ data: new Uint8Array(accountSpace), executable: false, lamports: BigInt(fundingLamports), owner: programClient.programAddress, }); }); }); ================================================ FILE: packages/dynamic-client/test/programs/system-program/initialize-nonce-account.test.ts ================================================ import { beforeEach, describe, expect, test } from 'vitest'; import type { SystemProgramClient } from '../generated/system-program-idl-types'; import { createTestProgramClient, SvmTestContext } from '../test-utils'; describe('System Program: initializeNonceAccount', () => { const programClient = createTestProgramClient('system-program-idl.json'); let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext(); }); test('should initialize a nonce account with specified authority', async () => { const payer = await ctx.createFundedAccount(); const nonceAccount = await ctx.createAccount(); const nonceAuthority = await ctx.createAccount(); const nonceAccountSpace = 80; const fundingLamports = 10_000_000; const createAccountInstruction = await programClient.methods .createAccount({ lamports: fundingLamports, programAddress: programClient.programAddress, space: nonceAccountSpace, }) .accounts({ newAccount: nonceAccount, payer, }) .instruction(); await ctx.sendInstruction(createAccountInstruction, [payer, nonceAccount]); const createdAccount = ctx.requireEncodedAccount(nonceAccount); expect(createdAccount.data.length).toBe(nonceAccountSpace); const initializeNonceInstruction = await programClient.methods .initializeNonceAccount({ nonceAuthority, }) .accounts({ nonceAccount, }) .instruction(); await ctx.sendInstruction(initializeNonceInstruction, [payer]); const initializedAccount = ctx.requireEncodedAccount(nonceAccount); expect(initializedAccount).toMatchObject({ executable: false, lamports: BigInt(fundingLamports), owner: programClient.programAddress, }); expect(initializedAccount.data.length).toBe(nonceAccountSpace); expect(initializedAccount.data.some(byte => byte !== 0)).toBe(true); }); test('should initialize a nonce account where authority is also the payer', async () => { const payerAndAuthority = await ctx.createFundedAccount(); const nonceAccount = await ctx.createAccount(); const nonceAccountSpace = 80; const fundingLamports = 5_000_000; const createAccountInstruction = await programClient.methods .createAccount({ lamports: fundingLamports, programAddress: programClient.programAddress, space: nonceAccountSpace, }) .accounts({ newAccount: nonceAccount, payer: payerAndAuthority, }) .instruction(); await ctx.sendInstruction(createAccountInstruction, [payerAndAuthority, nonceAccount]); const initializeNonceInstruction = await programClient.methods .initializeNonceAccount({ nonceAuthority: payerAndAuthority, }) .accounts({ nonceAccount, }) .instruction(); await ctx.sendInstruction(initializeNonceInstruction, [payerAndAuthority]); const initializedAccount = ctx.requireEncodedAccount(nonceAccount); expect(initializedAccount).toMatchObject({ executable: false, lamports: BigInt(fundingLamports), owner: programClient.programAddress, }); expect(initializedAccount.data.length).toBe(nonceAccountSpace); }); }); ================================================ FILE: packages/dynamic-client/test/programs/system-program/transfer-sol-with-seed.test.ts ================================================ import { beforeEach, describe, expect, test } from 'vitest'; import type { SystemProgramClient } from '../generated/system-program-idl-types'; import { createTestProgramClient, SvmTestContext } from '../test-utils'; describe('System Program: transferSolWithSeed', () => { const programClient = createTestProgramClient('system-program-idl.json'); let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext(); }); test('should transfer SOL from a seed-derived account to a destination', async () => { const payerAccount = await ctx.createFundedAccount(); const baseAccount = await ctx.createFundedAccount(); const seed = 'vault'; const source = await ctx.createAccountWithSeed(baseAccount, seed, programClient.programAddress); const fundingLamports = 10_000_000; const createIx = await programClient.methods .createAccountWithSeed({ amount: fundingLamports, base: baseAccount, programAddress: programClient.programAddress, seed, space: 0, }) .accounts({ baseAccount, newAccount: source, payer: payerAccount, }) .instruction(); await ctx.sendInstruction(createIx, [payerAccount, baseAccount]); const destination = await ctx.createAccount(); const transferAmount = 3_000_000; expect(ctx.requireEncodedAccount(source).lamports).toBe(BigInt(fundingLamports)); expect(ctx.fetchEncodedAccount(destination)).toBeNull(); const transferIx = await programClient.methods .transferSolWithSeed({ amount: transferAmount, fromOwner: programClient.programAddress, fromSeed: seed, }) .accounts({ baseAccount, destination, source, }) .instruction(); await ctx.sendInstruction(transferIx, [baseAccount]); const sourceAfter = ctx.requireEncodedAccount(source); const destinationAfter = ctx.requireEncodedAccount(destination); expect(sourceAfter.lamports).toBe(BigInt(fundingLamports) - BigInt(transferAmount)); expect(destinationAfter.lamports).toBe(BigInt(transferAmount)); }); }); ================================================ FILE: packages/dynamic-client/test/programs/system-program/transfer-sol.test.ts ================================================ import { beforeEach, describe, expect, test } from 'vitest'; import type { SystemProgramClient } from '../generated/system-program-idl-types'; import { createTestProgramClient, SvmTestContext } from '../test-utils'; describe('System Program: transferSol', () => { const programClient = createTestProgramClient('system-program-idl.json'); let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext(); }); test('should transfer SOL from one account to another', async () => { const initialSourceBalance = 3_000_000_000; const source = await ctx.createFundedAccount(BigInt(initialSourceBalance)); const destination = await ctx.createAccount(); const transferAmount = 1_000_000_000; expect(ctx.fetchEncodedAccount(source)).toMatchObject({ lamports: BigInt(initialSourceBalance), }); expect(ctx.fetchEncodedAccount(destination)).toBeNull(); const instruction = await programClient.methods .transferSol({ amount: transferAmount }) .accounts({ destination, source }) .instruction(); await ctx.sendInstruction(instruction, [source]); const sourceAccount = ctx.requireEncodedAccount(source); expect(sourceAccount.lamports).toBeLessThan(BigInt(initialSourceBalance) - BigInt(transferAmount)); const destinationAccount = ctx.requireEncodedAccount(destination); expect(destinationAccount.lamports).toBe(BigInt(transferAmount)); }); }); ================================================ FILE: packages/dynamic-client/test/programs/system-program/upgrade-nonce-account.test.ts ================================================ import { beforeEach, describe, expect, test } from 'vitest'; import type { SystemProgramClient } from '../generated/system-program-idl-types'; import { createTestProgramClient, SvmTestContext } from '../test-utils'; /** * * NOTE: This instruction only works on LEGACY nonce accounts (created before * the version field was added). When we create new nonce accounts with * initializeNonceAccount, they are already in the CURRENT format, so calling * upgradeNonceAccount on them will fail with "InvalidArgument". * * These tests verify that the instruction can be built correctly, but cannot * test the actual upgrade behavior since we cannot easily create legacy nonce * accounts in the test environment. */ describe('System Program: upgradeNonceAccount', () => { const programClient = createTestProgramClient('system-program-idl.json'); let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext(); }); test('smoke: should build upgrade nonce account instruction correctly', async () => { const nonceAccount = await ctx.createAccount(); const upgradeNonceInstruction = await programClient.methods .upgradeNonceAccount() .accounts({ nonceAccount, }) .instruction(); expect(upgradeNonceInstruction).toBeDefined(); expect(upgradeNonceInstruction.programAddress).toBe(programClient.programAddress); expect(upgradeNonceInstruction.accounts).toBeDefined(); expect(upgradeNonceInstruction.data).toBeDefined(); expect(upgradeNonceInstruction.accounts?.length).toBe(1); const nonceAccountMeta = upgradeNonceInstruction.accounts?.[0]; expect(nonceAccountMeta?.address).toBe(nonceAccount); }); }); ================================================ FILE: packages/dynamic-client/test/programs/system-program/withdraw-nonce-account.test.ts ================================================ import { beforeEach, describe, expect, test } from 'vitest'; import type { SystemProgramClient } from '../generated/system-program-idl-types'; import { createTestProgramClient, SvmTestContext } from '../test-utils'; describe('System Program: withdrawNonceAccount', () => { const programClient = createTestProgramClient('system-program-idl.json'); let ctx: SvmTestContext; beforeEach(() => { ctx = new SvmTestContext(); }); test('should withdraw lamports from nonce account to recipient', async () => { const payer = await ctx.createFundedAccount(); const nonceAccount = await ctx.createAccount(); const nonceAuthority = await ctx.createFundedAccount(); const recipient = await ctx.createAccount(); const nonceAccountSpace = 80; const fundingLamports = 10_000_000; const withdrawAmount = 2_000_000; const createAccountInstruction = await programClient.methods .createAccount({ lamports: fundingLamports, programAddress: programClient.programAddress, space: nonceAccountSpace, }) .accounts({ newAccount: nonceAccount, payer, }) .instruction(); await ctx.sendInstruction(createAccountInstruction, [payer, nonceAccount]); const initializeNonceInstruction = await programClient.methods .initializeNonceAccount({ nonceAuthority, }) .accounts({ nonceAccount, }) .instruction(); await ctx.sendInstruction(initializeNonceInstruction, [payer]); const beforeWithdraw = ctx.requireEncodedAccount(nonceAccount); expect(beforeWithdraw.lamports).toBe(BigInt(fundingLamports)); const withdrawInstruction = await programClient.methods .withdrawNonceAccount({ withdrawAmount, }) .accounts({ nonceAccount, nonceAuthority, recipientAccount: recipient, }) .instruction(); await ctx.sendInstruction(withdrawInstruction, [nonceAuthority]); const afterWithdrawNonce = ctx.requireEncodedAccount(nonceAccount); expect(afterWithdrawNonce.lamports).toBe(BigInt(fundingLamports - withdrawAmount)); const recipientAccount = ctx.requireEncodedAccount(recipient); expect(recipientAccount.lamports).toBe(BigInt(withdrawAmount)); }); }); ================================================ FILE: packages/dynamic-client/test/programs/test-utils.ts ================================================ import { readFileSync } from 'node:fs'; import path from 'node:path'; import { createFromJson, type RootNode } from 'codama'; import type { IdlInput, ProgramClient } from '../../src'; import { createProgramClient } from '../../src'; export function loadIdl(idlFileName: string, baseDir?: string): IdlInput { const basePath = baseDir ?? path.resolve(__dirname, 'idls'); const idlPath = path.resolve(basePath, idlFileName); const idlJson: unknown = JSON.parse(readFileSync(idlPath, 'utf8')); if (typeof idlJson !== 'object' || idlJson === null) { throw new Error(`Invalid IDL json: ${idlFileName}`); } return idlJson as IdlInput; } /** * Creates a program client for tests. Pass a generated client type for full type safety: * ```ts * import type { SystemProgramClient } from '../generated/system-program-idl-types'; * const client = createTestProgramClient('system-program-idl.json'); * // client.methods.advanceNonceAccount etc. are now typed, no non-null assertions needed * ``` */ export function createTestProgramClient(idlFileName: string): T { const idl = loadIdl(idlFileName); return createProgramClient(idl); } export function loadRoot(idlFileName: string): RootNode { const idl = loadIdl(idlFileName); const json = JSON.stringify(idl); return createFromJson(json).getRoot(); } export { SvmTestContext, type EncodedAccount } from '../svm-test-context'; ================================================ FILE: packages/dynamic-client/test/programs/token/amount-to-ui-amount.test.ts ================================================ import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, tokenClient } from './token-test-utils'; describe('Token Program: amountToUiAmount', () => { test('should convert a token amount to its UI representation', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); await createMint(ctx, payer, mintAccount, payer); const ix = await tokenClient.methods .amountToUiAmount({ amount: 1_000_000_000 }) .accounts({ mint: mintAccount }) .instruction(); const meta = await ctx.sendInstruction(ix, [payer]); const returnData = meta.returnData(); const uiAmount = new TextDecoder().decode(returnData.data()); expect(uiAmount).toBe('1'); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token/approve-checked.test.ts ================================================ import { getTokenDecoder } from '@solana-program/token'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, createTokenAccount, tokenClient } from './token-test-utils'; describe('Token Program: approveChecked', () => { test('should approve a delegate with mint and decimals verification', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const sourceAccount = await ctx.createAccount(); const delegate = await ctx.createAccount(); await createMint(ctx, payer, mintAccount, payer); await createTokenAccount(ctx, payer, sourceAccount, mintAccount, payer); const mintIx = await tokenClient.methods .mintTo({ amount: 1_000_000 }) .accounts({ mint: mintAccount, mintAuthority: payer, token: sourceAccount }) .instruction(); await ctx.sendInstruction(mintIx, [payer]); const ix = await tokenClient.methods .approveChecked({ amount: 500_000, decimals: 9 }) .accounts({ delegate, mint: mintAccount, owner: payer, source: sourceAccount }) .instruction(); await ctx.sendInstruction(ix, [payer]); const decoder = getTokenDecoder(); const sourceData = decoder.decode(ctx.requireEncodedAccount(sourceAccount).data); expect(sourceData.delegate).toStrictEqual({ __option: 'Some', value: delegate }); expect(sourceData.delegatedAmount).toBe(500_000n); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token/approve.test.ts ================================================ import { getTokenDecoder } from '@solana-program/token'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, createTokenAccount, SPL_TOKEN_MULTISIG_SIZE, systemClient, tokenClient } from './token-test-utils'; describe('Token Program: approve', () => { test('should approve a delegate for a token account', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const sourceAccount = await ctx.createAccount(); const delegate = await ctx.createAccount(); await createMint(ctx, payer, mintAccount, payer); await createTokenAccount(ctx, payer, sourceAccount, mintAccount, payer); const mintIx = await tokenClient.methods .mintTo({ amount: 1_000_000 }) .accounts({ mint: mintAccount, mintAuthority: payer, token: sourceAccount }) .instruction(); await ctx.sendInstruction(mintIx, [payer]); const ix = await tokenClient.methods .approve({ amount: 500_000 }) .accounts({ delegate, owner: payer, source: sourceAccount }) .instruction(); await ctx.sendInstruction(ix, [payer]); const decoder = getTokenDecoder(); const sourceData = decoder.decode(ctx.requireEncodedAccount(sourceAccount).data); expect(sourceData.delegate).toStrictEqual({ __option: 'Some', value: delegate }); expect(sourceData.delegatedAmount).toBe(500_000n); }); test('should approve with multisig', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const sourceAccount = await ctx.createAccount(); const delegate = await ctx.createAccount(); const multisigOwner = await ctx.createAccount(); // Create mints await createMint(ctx, payer, mintAccount, payer); await createTokenAccount(ctx, payer, sourceAccount, mintAccount, multisigOwner); const mintIx = await tokenClient.methods .mintTo({ amount: 1_000_000 }) .accounts({ mint: mintAccount, mintAuthority: payer, token: sourceAccount }) .instruction(); await ctx.sendInstruction(mintIx, [payer]); // Create multisignature owner const signer1 = await ctx.createAccount(); const signer2 = await ctx.createAccount(); const signer3 = await ctx.createAccount(); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(SPL_TOKEN_MULTISIG_SIZE)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: tokenClient.programAddress, space: SPL_TOKEN_MULTISIG_SIZE, }) .accounts({ newAccount: multisigOwner, payer }) .instruction(); const initMultisigIx = await tokenClient.methods .initializeMultisig({ m: 2, signers: [signer1, signer2, signer3] }) .accounts({ multisig: multisigOwner }) .instruction(); await ctx.sendInstructions([createAccountIx, initMultisigIx], [payer, multisigOwner]); // Approve delegate with multisig owner, // providing signer1 and signer2 without signing by multisigOwner const ix = await tokenClient.methods .approve({ amount: 500_000, multiSigners: [signer1, signer2] }) .accounts({ delegate, owner: multisigOwner, source: sourceAccount }) .instruction(); await ctx.sendInstruction(ix, [payer, signer1, signer2]); const decoder = getTokenDecoder(); const sourceData = decoder.decode(ctx.requireEncodedAccount(sourceAccount).data); expect(sourceData.delegate).toStrictEqual({ __option: 'Some', value: delegate }); expect(sourceData.delegatedAmount).toBe(500_000n); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token/burn-checked.test.ts ================================================ import { getTokenDecoder } from '@solana-program/token'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, createTokenAccount, tokenClient } from './token-test-utils'; describe('Token Program: burnChecked', () => { test('should burn tokens with decimals verification', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const tokenAccount = await ctx.createAccount(); await createMint(ctx, payer, mintAccount, payer); await createTokenAccount(ctx, payer, tokenAccount, mintAccount, payer); const mintIx = await tokenClient.methods .mintTo({ amount: 1_000_000 }) .accounts({ mint: mintAccount, mintAuthority: payer, token: tokenAccount }) .instruction(); await ctx.sendInstruction(mintIx, [payer]); const ix = await tokenClient.methods .burnChecked({ amount: 400_000, decimals: 9 }) .accounts({ account: tokenAccount, authority: payer, mint: mintAccount }) .instruction(); await ctx.sendInstruction(ix, [payer]); const decoder = getTokenDecoder(); const tokenData = decoder.decode(ctx.requireEncodedAccount(tokenAccount).data); expect(tokenData.amount).toBe(600_000n); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token/burn.test.ts ================================================ import { getMintDecoder, getTokenDecoder } from '@solana-program/token'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, createTokenAccount, tokenClient } from './token-test-utils'; describe('Token Program: burn', () => { test('should burn tokens from a token account', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const tokenAccount = await ctx.createAccount(); await createMint(ctx, payer, mintAccount, payer); await createTokenAccount(ctx, payer, tokenAccount, mintAccount, payer); // Mint tokens first. const mintIx = await tokenClient.methods .mintTo({ amount: 1_000_000 }) .accounts({ mint: mintAccount, mintAuthority: payer, token: tokenAccount }) .instruction(); await ctx.sendInstruction(mintIx, [payer]); // Burn tokens. const burnIx = await tokenClient.methods .burn({ amount: 400_000 }) .accounts({ account: tokenAccount, authority: payer, mint: mintAccount }) .instruction(); await ctx.sendInstruction(burnIx, [payer]); // Verify token account balance decreased. const tokenData = getTokenDecoder().decode(ctx.requireEncodedAccount(tokenAccount).data); expect(tokenData.amount).toBe(600_000n); // Verify mint supply decreased. const mintData = getMintDecoder().decode(ctx.requireEncodedAccount(mintAccount).data); expect(mintData.supply).toBe(600_000n); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token/close-account.test.ts ================================================ import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, createTokenAccount, tokenClient } from './token-test-utils'; describe('Token Program: closeAccount', () => { test('should close a token account and transfer lamports to destination', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const tokenAccount = await ctx.createAccount(); const owner = await ctx.createFundedAccount(); await createMint(ctx, payer, mintAccount, payer); await createTokenAccount(ctx, payer, tokenAccount, mintAccount, owner); const destBalanceBefore = ctx.getBalanceOrZero(owner); const ix = await tokenClient.methods .closeAccount() .accounts({ account: tokenAccount, destination: owner, owner }) .instruction(); await ctx.sendInstruction(ix, [owner]); expect(ctx.fetchEncodedAccount(tokenAccount)).toBeNull(); expect(ctx.getBalanceOrZero(owner)).toBeGreaterThan(destBalanceBefore); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token/freeze-account.test.ts ================================================ import { AccountState, getTokenDecoder } from '@solana-program/token'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, createTokenAccount, tokenClient } from './token-test-utils'; describe('Token Program: freezeAccount', () => { test('should freeze a token account', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const tokenAccount = await ctx.createAccount(); const freezeAuthority = await ctx.createFundedAccount(); await createMint(ctx, payer, mintAccount, payer, freezeAuthority); await createTokenAccount(ctx, payer, tokenAccount, mintAccount, payer); const freezeIx = await tokenClient.methods .freezeAccount() .accounts({ account: tokenAccount, mint: mintAccount, owner: freezeAuthority }) .instruction(); await ctx.sendInstruction(freezeIx, [freezeAuthority]); const account = ctx.requireEncodedAccount(tokenAccount); const tokenData = getTokenDecoder().decode(account.data); expect(tokenData.state).toBe(AccountState.Frozen); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token/get-account-data-size.test.ts ================================================ import { getU64Decoder } from '@solana/codecs'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, SPL_TOKEN_ACCOUNT_SIZE, tokenClient } from './token-test-utils'; describe('Token Program: getAccountDataSize', () => { test('should return the required account size for a given mint', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); await createMint(ctx, payer, mintAccount, payer); const ix = await tokenClient.methods.getAccountDataSize().accounts({ mint: mintAccount }).instruction(); const meta = await ctx.sendInstruction(ix, [payer]); const size = getU64Decoder().decode(meta.returnData().data()); expect(size).toBe(BigInt(SPL_TOKEN_ACCOUNT_SIZE)); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token/initialize-account.test.ts ================================================ import { AccountState, getTokenDecoder } from '@solana-program/token'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, createTokenAccount } from './token-test-utils'; describe('Token Program: initializeAccount', () => { test('should initialize a token account', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const tokenAccount = await ctx.createAccount(); const owner = await ctx.createAccount(); await createMint(ctx, payer, mintAccount, payer); await createTokenAccount(ctx, payer, tokenAccount, mintAccount, owner); const tokenData = getTokenDecoder().decode(ctx.requireEncodedAccount(tokenAccount).data); expect(tokenData.mint).toBe(mintAccount); expect(tokenData.owner).toBe(owner); expect(tokenData.amount).toBe(0n); expect(tokenData.state).toBe(AccountState.Initialized); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token/initialize-account2.test.ts ================================================ import { AccountState, getTokenDecoder } from '@solana-program/token'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, SPL_TOKEN_ACCOUNT_SIZE, systemClient, tokenClient } from './token-test-utils'; describe('Token Program: initializeAccount2', () => { test('should initialize a token account with owner passed as instruction data', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const tokenAccount = await ctx.createAccount(); const owner = await ctx.createAccount(); await createMint(ctx, payer, mintAccount, payer); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(SPL_TOKEN_ACCOUNT_SIZE)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: tokenClient.programAddress, space: SPL_TOKEN_ACCOUNT_SIZE, }) .accounts({ newAccount: tokenAccount, payer }) .instruction(); const initAccountIx = await tokenClient.methods .initializeAccount2({ owner }) .accounts({ account: tokenAccount, mint: mintAccount }) .instruction(); await ctx.sendInstructions([createAccountIx, initAccountIx], [payer, tokenAccount]); const decoder = getTokenDecoder(); const tokenData = decoder.decode(ctx.requireEncodedAccount(tokenAccount).data); expect(tokenData.mint).toBe(mintAccount); expect(tokenData.owner).toBe(owner); expect(tokenData.state).toBe(AccountState.Initialized); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token/initialize-account3.test.ts ================================================ import { AccountState, getTokenDecoder } from '@solana-program/token'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, SPL_TOKEN_ACCOUNT_SIZE, systemClient, tokenClient } from './token-test-utils'; describe('Token Program: initializeAccount3', () => { test('should initialize a token account without requiring the Rent sysvar', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const tokenAccount = await ctx.createAccount(); const owner = await ctx.createAccount(); await createMint(ctx, payer, mintAccount, payer); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(SPL_TOKEN_ACCOUNT_SIZE)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: tokenClient.programAddress, space: SPL_TOKEN_ACCOUNT_SIZE, }) .accounts({ newAccount: tokenAccount, payer }) .instruction(); const initAccountIx = await tokenClient.methods .initializeAccount3({ owner }) .accounts({ account: tokenAccount, mint: mintAccount }) .instruction(); await ctx.sendInstructions([createAccountIx, initAccountIx], [payer, tokenAccount]); const decoder = getTokenDecoder(); const tokenData = decoder.decode(ctx.requireEncodedAccount(tokenAccount).data); expect(tokenData.mint).toBe(mintAccount); expect(tokenData.owner).toBe(owner); expect(tokenData.state).toBe(AccountState.Initialized); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token/initialize-immutable-owner.test.ts ================================================ import { getTokenDecoder } from '@solana-program/token'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, SPL_TOKEN_ACCOUNT_SIZE, systemClient, tokenClient } from './token-test-utils'; describe('Token Program: initializeImmutableOwner', () => { test('should initialize immutable owner on a token account before initializeAccount', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const tokenAccount = await ctx.createAccount(); await createMint(ctx, payer, mintAccount, payer); const rent = ctx.getMinimumBalanceForRentExemption(BigInt(SPL_TOKEN_ACCOUNT_SIZE)); const createAccountIx = await systemClient.methods .createAccount({ lamports: rent, programAddress: tokenClient.programAddress, space: SPL_TOKEN_ACCOUNT_SIZE, }) .accounts({ newAccount: tokenAccount, payer }) .instruction(); const initImmutableOwnerIx = await tokenClient.methods .initializeImmutableOwner() .accounts({ account: tokenAccount }) .instruction(); const initAccountIx = await tokenClient.methods .initializeAccount() .accounts({ account: tokenAccount, mint: mintAccount, owner: payer }) .instruction(); await ctx.sendInstructions([createAccountIx, initImmutableOwnerIx, initAccountIx], [payer, tokenAccount]); const account = ctx.requireEncodedAccount(tokenAccount); const tokenData = getTokenDecoder().decode(account.data); expect(tokenData.mint).toBe(mintAccount); expect(tokenData.owner).toBe(payer); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token/initialize-mint.test.ts ================================================ import { getMintDecoder } from '@solana-program/token'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { SPL_TOKEN_MINT_SIZE, systemClient, tokenClient } from './token-test-utils'; describe('Token Program: initializeMint', () => { test('should initialize a mint with default freeze authority (None)', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const mintRent = ctx.getMinimumBalanceForRentExemption(BigInt(SPL_TOKEN_MINT_SIZE)); const createAccountIx = await systemClient.methods .createAccount({ lamports: mintRent, programAddress: tokenClient.programAddress, space: SPL_TOKEN_MINT_SIZE, }) .accounts({ newAccount: mintAccount, payer, }) .instruction(); const initMintIx = await tokenClient.methods .initializeMint({ decimals: 9, mintAuthority: payer }) .accounts({ mint: mintAccount }) .instruction(); await ctx.sendInstructions([createAccountIx, initMintIx], [payer, mintAccount]); const mintData = getMintDecoder().decode(ctx.requireEncodedAccount(mintAccount).data); expect(mintData.mintAuthority).toEqual({ __option: 'Some', value: payer }); expect(mintData.decimals).toBe(9); expect(mintData.supply).toBe(0n); expect(mintData.freezeAuthority).toEqual({ __option: 'None' }); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token/initialize-mint2.test.ts ================================================ import { getMintDecoder } from '@solana-program/token'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { SPL_TOKEN_MINT_SIZE, systemClient, tokenClient } from './token-test-utils'; describe('Token Program: initializeMint2', () => { test('should initialize a mint without requiring the Rent sysvar', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const freezeAuthority = await ctx.createAccount(); const mintRent = ctx.getMinimumBalanceForRentExemption(BigInt(SPL_TOKEN_MINT_SIZE)); const createAccountIx = await systemClient.methods .createAccount({ lamports: mintRent, programAddress: tokenClient.programAddress, space: SPL_TOKEN_MINT_SIZE, }) .accounts({ newAccount: mintAccount, payer, }) .instruction(); const initMintIx = await tokenClient.methods .initializeMint2({ decimals: 6, freezeAuthority, mintAuthority: payer }) .accounts({ mint: mintAccount }) .instruction(); await ctx.sendInstructions([createAccountIx, initMintIx], [payer, mintAccount]); const mintData = getMintDecoder().decode(ctx.requireEncodedAccount(mintAccount).data); expect(mintData.mintAuthority).toEqual({ __option: 'Some', value: payer }); expect(mintData.decimals).toBe(6); expect(mintData.supply).toBe(0n); expect(mintData.freezeAuthority).toEqual({ __option: 'Some', value: freezeAuthority }); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token/initialize-multisig.test.ts ================================================ import { getMultisigDecoder } from '@solana-program/token'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { SPL_TOKEN_MULTISIG_SIZE, systemClient, tokenClient } from './token-test-utils'; describe('Token Program: initializeMultisig', () => { test('should initialize a multisig account with 2-of-3 signers', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const multisigAccount = await ctx.createAccount(); const signer1 = await ctx.createAccount(); const signer2 = await ctx.createAccount(); const signer3 = await ctx.createAccount(); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(SPL_TOKEN_MULTISIG_SIZE)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: tokenClient.programAddress, space: SPL_TOKEN_MULTISIG_SIZE, }) .accounts({ newAccount: multisigAccount, payer }) .instruction(); const initMultisigIx = await tokenClient.methods .initializeMultisig({ m: 2, signers: [signer1, signer2, signer3] }) .accounts({ multisig: multisigAccount }) .instruction(); await ctx.sendInstructions([createAccountIx, initMultisigIx], [payer, multisigAccount]); const decoder = getMultisigDecoder(); const multisigData = decoder.decode(ctx.requireEncodedAccount(multisigAccount).data); expect(multisigData.m).toBe(2); expect(multisigData.n).toBe(3); expect(multisigData.isInitialized).toBe(true); expect(multisigData.signers.slice(0, 3)).toStrictEqual([signer1, signer2, signer3]); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token/initialize-multisig2.test.ts ================================================ import { getMultisigDecoder } from '@solana-program/token'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { SPL_TOKEN_MULTISIG_SIZE, systemClient, tokenClient } from './token-test-utils'; describe('Token Program: initializeMultisig2', () => { test('should initialize a multisig account without requiring the Rent sysvar', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const multisigAccount = await ctx.createAccount(); const signer1 = await ctx.createAccount(); const signer2 = await ctx.createAccount(); const signer3 = await ctx.createAccount(); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(SPL_TOKEN_MULTISIG_SIZE)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: tokenClient.programAddress, space: SPL_TOKEN_MULTISIG_SIZE, }) .accounts({ newAccount: multisigAccount, payer }) .instruction(); const initMultisigIx = await tokenClient.methods .initializeMultisig2({ m: 2, signers: [signer1, signer2, signer3] }) .accounts({ multisig: multisigAccount }) .instruction(); await ctx.sendInstructions([createAccountIx, initMultisigIx], [payer, multisigAccount]); const decoder = getMultisigDecoder(); const multisigData = decoder.decode(ctx.requireEncodedAccount(multisigAccount).data); expect(multisigData.m).toBe(2); expect(multisigData.n).toBe(3); expect(multisigData.isInitialized).toBe(true); expect(multisigData.signers.slice(0, 3)).toStrictEqual([signer1, signer2, signer3]); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token/mint-to-checked.test.ts ================================================ import { getTokenDecoder } from '@solana-program/token'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, createTokenAccount, tokenClient } from './token-test-utils'; describe('Token Program: mintToChecked', () => { test('should mint tokens with decimals verification', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const tokenAccount = await ctx.createAccount(); await createMint(ctx, payer, mintAccount, payer); await createTokenAccount(ctx, payer, tokenAccount, mintAccount, payer); const ix = await tokenClient.methods .mintToChecked({ amount: 1_000_000, decimals: 9 }) .accounts({ mint: mintAccount, mintAuthority: payer, token: tokenAccount }) .instruction(); await ctx.sendInstruction(ix, [payer]); const decoder = getTokenDecoder(); const tokenData = decoder.decode(ctx.requireEncodedAccount(tokenAccount).data); expect(tokenData.amount).toBe(1_000_000n); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token/mint-to.test.ts ================================================ import { getTokenDecoder } from '@solana-program/token'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, createTokenAccount, tokenClient } from './token-test-utils'; describe('Token Program: mintTo', () => { test('should mint tokens to a token account', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const tokenAccount = await ctx.createAccount(); await createMint(ctx, payer, mintAccount, payer); await createTokenAccount(ctx, payer, tokenAccount, mintAccount, payer); const ix = await tokenClient.methods .mintTo({ amount: 1_000_000 }) .accounts({ mint: mintAccount, mintAuthority: payer, token: tokenAccount }) .instruction(); await ctx.sendInstruction(ix, [payer]); const account = ctx.requireEncodedAccount(tokenAccount); const tokenData = getTokenDecoder().decode(account.data); expect(tokenData.amount).toBe(1_000_000n); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token/revoke.test.ts ================================================ import { getTokenDecoder } from '@solana-program/token'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, createTokenAccount, tokenClient } from './token-test-utils'; describe('Token Program: revoke', () => { test('should revoke a delegate from a token account', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const sourceAccount = await ctx.createAccount(); const delegate = await ctx.createAccount(); await createMint(ctx, payer, mintAccount, payer); await createTokenAccount(ctx, payer, sourceAccount, mintAccount, payer); const mintIx = await tokenClient.methods .mintTo({ amount: 1_000_000 }) .accounts({ mint: mintAccount, mintAuthority: payer, token: sourceAccount }) .instruction(); await ctx.sendInstruction(mintIx, [payer]); const approveIx = await tokenClient.methods .approve({ amount: 500_000 }) .accounts({ delegate, owner: payer, source: sourceAccount }) .instruction(); await ctx.sendInstruction(approveIx, [payer]); const ix = await tokenClient.methods.revoke().accounts({ owner: payer, source: sourceAccount }).instruction(); await ctx.sendInstruction(ix, [payer]); const decoder = getTokenDecoder(); const sourceData = decoder.decode(ctx.requireEncodedAccount(sourceAccount).data); expect(sourceData.delegate).toStrictEqual({ __option: 'None' }); expect(sourceData.delegatedAmount).toBe(0n); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token/set-authority.test.ts ================================================ import { getMintDecoder } from '@solana-program/token'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, tokenClient } from './token-test-utils'; describe('Token Program: setAuthority', () => { test('should change the mint authority to a new address', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const newAuthority = await ctx.createAccount(); await createMint(ctx, payer, mintAccount, payer); const ix = await tokenClient.methods .setAuthority({ authorityType: 'mintTokens', newAuthority }) .accounts({ owned: mintAccount, owner: payer }) .instruction(); await ctx.sendInstruction(ix, [payer]); const decoder = getMintDecoder(); const mintData = decoder.decode(ctx.requireEncodedAccount(mintAccount).data); expect(mintData.mintAuthority).toStrictEqual({ __option: 'Some', value: newAuthority }); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token/sync-native.test.ts ================================================ import { address } from '@solana/addresses'; import { getTokenDecoder } from '@solana-program/token'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { SPL_TOKEN_ACCOUNT_SIZE, systemClient, tokenClient } from './token-test-utils'; const NATIVE_MINT = address('So11111111111111111111111111111111111111112'); describe('Token Program: syncNative', () => { test('should sync a wrapped SOL account amount with its lamport balance', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const wrappedSolAccount = await ctx.createAccount(); // Create and initialize a wrapped SOL token account. const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(SPL_TOKEN_ACCOUNT_SIZE)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: tokenClient.programAddress, space: SPL_TOKEN_ACCOUNT_SIZE, }) .accounts({ newAccount: wrappedSolAccount, payer }) .instruction(); const initAccountIx = await tokenClient.methods .initializeAccount() .accounts({ account: wrappedSolAccount, mint: NATIVE_MINT, owner: payer }) .instruction(); await ctx.sendInstructions([createAccountIx, initAccountIx], [payer, wrappedSolAccount]); // Transfer additional SOL to the wrapped account via system program. const transferAmount = 1_000_000_000n; const transferIx = await systemClient.methods .transferSol({ amount: transferAmount }) .accounts({ destination: wrappedSolAccount, source: payer }) .instruction(); await ctx.sendInstruction(transferIx, [payer]); // Token amount is still 0 before sync. const decoder = getTokenDecoder(); const beforeSync = decoder.decode(ctx.requireEncodedAccount(wrappedSolAccount).data); expect(beforeSync.amount).toBe(0n); // Sync native to update the token amount. const syncIx = await tokenClient.methods.syncNative().accounts({ account: wrappedSolAccount }).instruction(); await ctx.sendInstruction(syncIx, [payer]); const afterSync = decoder.decode(ctx.requireEncodedAccount(wrappedSolAccount).data); expect(afterSync.amount).toBe(transferAmount); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token/thaw-account.test.ts ================================================ import { AccountState, getTokenDecoder } from '@solana-program/token'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, createTokenAccount, tokenClient } from './token-test-utils'; describe('Token Program: thawAccount', () => { test('should thaw a frozen account', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const tokenAccount = await ctx.createAccount(); const freezeAuthority = await ctx.createFundedAccount(); await createMint(ctx, payer, mintAccount, payer, freezeAuthority); await createTokenAccount(ctx, payer, tokenAccount, mintAccount, payer); const freezeIx = await tokenClient.methods .freezeAccount() .accounts({ account: tokenAccount, mint: mintAccount, owner: freezeAuthority }) .instruction(); await ctx.sendInstruction(freezeIx, [freezeAuthority]); const thawIx = await tokenClient.methods .thawAccount() .accounts({ account: tokenAccount, mint: mintAccount, owner: freezeAuthority }) .instruction(); await ctx.sendInstruction(thawIx, [freezeAuthority]); const account = ctx.requireEncodedAccount(tokenAccount); const tokenData = getTokenDecoder().decode(account.data); expect(tokenData.state).toBe(AccountState.Initialized); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token/token-test-utils.ts ================================================ import type { Address } from '@solana/addresses'; import type { SystemProgramClient } from '../generated/system-program-idl-types'; import type { TokenProgramClient } from '../generated/token-idl-types'; import { createTestProgramClient, SvmTestContext } from '../test-utils'; export const tokenClient = createTestProgramClient('token-idl.json'); export const systemClient = createTestProgramClient('system-program-idl.json'); export const SPL_TOKEN_MINT_SIZE = 82; export const SPL_TOKEN_ACCOUNT_SIZE = 165; export const SPL_TOKEN_MULTISIG_SIZE = 355; export async function createMint( ctx: SvmTestContext, payer: Address, mint: Address, mintAuthority: Address, freezeAuthority?: Address, ): Promise { const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(SPL_TOKEN_MINT_SIZE)); const createMintAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: tokenClient.programAddress, space: SPL_TOKEN_MINT_SIZE }) .accounts({ newAccount: mint, payer }) .instruction(); await ctx.sendInstruction(createMintAccountIx, [payer, mint]); const initializeMintIx = await tokenClient.methods .initializeMint({ decimals: 9, freezeAuthority: freezeAuthority ?? null, mintAuthority }) .accounts({ mint }) .instruction(); await ctx.sendInstruction(initializeMintIx, [payer]); } export async function createTokenAccount( ctx: SvmTestContext, payer: Address, account: Address, mint: Address, owner: Address, ): Promise { const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(SPL_TOKEN_ACCOUNT_SIZE)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: tokenClient.programAddress, space: SPL_TOKEN_ACCOUNT_SIZE }) .accounts({ newAccount: account, payer }) .instruction(); const initAccountIx = await tokenClient.methods .initializeAccount() .accounts({ account, mint, owner }) .instruction(); await ctx.sendInstructions([createAccountIx, initAccountIx], [payer, account]); } ================================================ FILE: packages/dynamic-client/test/programs/token/transfer-checked.test.ts ================================================ import { getTokenDecoder } from '@solana-program/token'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, createTokenAccount, tokenClient } from './token-test-utils'; describe('Token Program: transferChecked', () => { test('should transfer tokens with mint and decimal verification', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const sourceAccount = await ctx.createAccount(); const destinationAccount = await ctx.createAccount(); await createMint(ctx, payer, mintAccount, payer); await createTokenAccount(ctx, payer, sourceAccount, mintAccount, payer); await createTokenAccount(ctx, payer, destinationAccount, mintAccount, payer); const mintIx = await tokenClient.methods .mintTo({ amount: 1_000_000 }) .accounts({ mint: mintAccount, mintAuthority: payer, token: sourceAccount }) .instruction(); await ctx.sendInstruction(mintIx, [payer]); const ix = await tokenClient.methods .transferChecked({ amount: 400_000, decimals: 9 }) .accounts({ authority: payer, destination: destinationAccount, mint: mintAccount, source: sourceAccount }) .instruction(); await ctx.sendInstruction(ix, [payer]); const decoder = getTokenDecoder(); const sourceData = decoder.decode(ctx.requireEncodedAccount(sourceAccount).data); const destData = decoder.decode(ctx.requireEncodedAccount(destinationAccount).data); expect(sourceData.amount).toBe(600_000n); expect(destData.amount).toBe(400_000n); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token/transfer.test.ts ================================================ import { getTokenDecoder } from '@solana-program/token'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, createTokenAccount, tokenClient } from './token-test-utils'; describe('Token Program: transfer', () => { test('should transfer tokens between accounts', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const sourceAccount = await ctx.createAccount(); const destinationAccount = await ctx.createAccount(); await createMint(ctx, payer, mintAccount, payer); await createTokenAccount(ctx, payer, sourceAccount, mintAccount, payer); await createTokenAccount(ctx, payer, destinationAccount, mintAccount, payer); const mintIx = await tokenClient.methods .mintTo({ amount: 1_000_000 }) .accounts({ mint: mintAccount, mintAuthority: payer, token: sourceAccount }) .instruction(); await ctx.sendInstruction(mintIx, [payer]); const ix = await tokenClient.methods .transfer({ amount: 400_000 }) .accounts({ authority: payer, destination: destinationAccount, source: sourceAccount }) .instruction(); await ctx.sendInstruction(ix, [payer]); const decoder = getTokenDecoder(); const sourceData = decoder.decode(ctx.requireEncodedAccount(sourceAccount).data); const destData = decoder.decode(ctx.requireEncodedAccount(destinationAccount).data); expect(sourceData.amount).toBe(600_000n); expect(destData.amount).toBe(400_000n); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token/ui-amount-to-amount.test.ts ================================================ import { getU64Decoder } from '@solana/codecs'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, tokenClient } from './token-test-utils'; describe('Token Program: uiAmountToAmount', () => { test('should convert a UI amount string to a raw token amount', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); await createMint(ctx, payer, mintAccount, payer); const ix = await tokenClient.methods .uiAmountToAmount({ uiAmount: '1' }) .accounts({ mint: mintAccount }) .instruction(); const meta = await ctx.sendInstruction(ix, [payer]); const rawAmount = getU64Decoder().decode(meta.returnData().data()); expect(rawAmount).toBe(1_000_000_000n); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/amount-to-ui-amount.test.ts ================================================ import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, token2022Client } from './token-2022-test-utils'; describe('Token 2022 Program: amountToUiAmount', () => { test('should convert a token amount to its UI representation', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); await createMint(ctx, payer, mintAccount, payer); const amount = 1_000_000_000; const expectedUiAmount = amount / 10 ** 9; const ix = await token2022Client.methods .amountToUiAmount({ amount }) .accounts({ mint: mintAccount }) .instruction(); const meta = await ctx.sendInstruction(ix, [payer]); const returnData = meta.returnData(); const uiAmount = new TextDecoder().decode(returnData.data()); expect(uiAmount).toBe(expectedUiAmount.toString()); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/approve-checked.test.ts ================================================ import { getTokenDecoder } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, createTokenAccount, mintTokens, token2022Client } from './token-2022-test-utils'; describe('Token 2022 Program: approveChecked', () => { test('should approve_checked a delegate', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const sourceAccount = await ctx.createAccount(); const delegate = await ctx.createAccount(); await createMint(ctx, payer, mintAccount, payer); await createTokenAccount(ctx, payer, sourceAccount, mintAccount, payer); await mintTokens(ctx, payer, mintAccount, sourceAccount, payer, 1_000_000); const ix = await token2022Client.methods .approveChecked({ amount: 500_000, decimals: 9 }) .accounts({ delegate, mint: mintAccount, owner: payer, source: sourceAccount }) .instruction(); await ctx.sendInstruction(ix, [payer]); const decoder = getTokenDecoder(); const sourceData = decoder.decode(ctx.requireEncodedAccount(sourceAccount).data); expect(sourceData.delegate).toStrictEqual({ __option: 'Some', value: delegate }); expect(sourceData.delegatedAmount).toBe(500_000n); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/approve.test.ts ================================================ import { getTokenDecoder } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, createTokenAccount, mintTokens, systemClient, TOKEN_2022_MULTISIG_SIZE, token2022Client, } from './token-2022-test-utils'; describe('Token 2022 Program: approve', () => { test('should approve a delegate for a token account', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const sourceAccount = await ctx.createAccount(); const delegate = await ctx.createAccount(); await createMint(ctx, payer, mintAccount, payer); await createTokenAccount(ctx, payer, sourceAccount, mintAccount, payer); await mintTokens(ctx, payer, mintAccount, sourceAccount, payer, 1_000_000); const ix = await token2022Client.methods .approve({ amount: 500_000 }) .accounts({ delegate, owner: payer, source: sourceAccount }) .instruction(); await ctx.sendInstruction(ix, [payer]); const decoder = getTokenDecoder(); const sourceData = decoder.decode(ctx.requireEncodedAccount(sourceAccount).data); expect(sourceData.delegate).toStrictEqual({ __option: 'Some', value: delegate }); expect(sourceData.delegatedAmount).toBe(500_000n); }); test('should approve with multisig', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const sourceAccount = await ctx.createAccount(); const delegate = await ctx.createAccount(); const multisigOwner = await ctx.createAccount(); await createMint(ctx, payer, mintAccount, payer); await createTokenAccount(ctx, payer, sourceAccount, mintAccount, multisigOwner); await mintTokens(ctx, payer, mintAccount, sourceAccount, payer, 1_000_000); const signer1 = await ctx.createAccount(); const signer2 = await ctx.createAccount(); const signer3 = await ctx.createAccount(); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(TOKEN_2022_MULTISIG_SIZE)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space: TOKEN_2022_MULTISIG_SIZE, }) .accounts({ newAccount: multisigOwner, payer }) .instruction(); const initMultisigIx = await token2022Client.methods .initializeMultisig({ m: 2, signers: [signer1, signer2, signer3] }) .accounts({ multisig: multisigOwner }) .instruction(); await ctx.sendInstructions([createAccountIx, initMultisigIx], [payer, multisigOwner]); const ix = await token2022Client.methods .approve({ amount: 500_000, multiSigners: [signer1, signer2] }) .accounts({ delegate, owner: multisigOwner, source: sourceAccount }) .instruction(); await ctx.sendInstruction(ix, [payer, signer1, signer2]); const decoder = getTokenDecoder(); const sourceData = decoder.decode(ctx.requireEncodedAccount(sourceAccount).data); expect(sourceData.delegate).toStrictEqual({ __option: 'Some', value: delegate }); expect(sourceData.delegatedAmount).toBe(500_000n); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/burn-checked.test.ts ================================================ import { getTokenDecoder } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, createTokenAccount, mintTokens, token2022Client } from './token-2022-test-utils'; describe('Token 2022 Program: burnChecked', () => { test('should burn_checked tokens', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const tokenAccount = await ctx.createAccount(); await createMint(ctx, payer, mintAccount, payer); await createTokenAccount(ctx, payer, tokenAccount, mintAccount, payer); await mintTokens(ctx, payer, mintAccount, tokenAccount, payer, 1_000_000); const ix = await token2022Client.methods .burnChecked({ amount: 400_000, decimals: 9 }) .accounts({ account: tokenAccount, authority: payer, mint: mintAccount }) .instruction(); await ctx.sendInstruction(ix, [payer]); const decoder = getTokenDecoder(); const tokenData = decoder.decode(ctx.requireEncodedAccount(tokenAccount).data); expect(tokenData.amount).toBe(600_000n); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/burn.test.ts ================================================ import { getMintDecoder, getTokenDecoder } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, createTokenAccount, mintTokens, token2022Client } from './token-2022-test-utils'; describe('Token 2022 Program: burn', () => { test('should burn tokens from a token account', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const tokenAccount = await ctx.createAccount(); await createMint(ctx, payer, mintAccount, payer); await createTokenAccount(ctx, payer, tokenAccount, mintAccount, payer); await mintTokens(ctx, payer, mintAccount, tokenAccount, payer, 1_000_000); const burnIx = await token2022Client.methods .burn({ amount: 400_000 }) .accounts({ account: tokenAccount, authority: payer, mint: mintAccount }) .instruction(); await ctx.sendInstruction(burnIx, [payer]); const tokenData = getTokenDecoder().decode(ctx.requireEncodedAccount(tokenAccount).data); expect(tokenData.amount).toBe(600_000n); const mintData = getMintDecoder().decode(ctx.requireEncodedAccount(mintAccount).data); expect(mintData.supply).toBe(600_000n); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/close-account.test.ts ================================================ import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, createTokenAccount, token2022Client } from './token-2022-test-utils'; describe('Token 2022 Program: closeAccount', () => { test('should close a token account', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const tokenAccount = await ctx.createAccount(); const owner = await ctx.createFundedAccount(); await createMint(ctx, payer, mintAccount, payer); await createTokenAccount(ctx, payer, tokenAccount, mintAccount, owner); const ix = await token2022Client.methods .closeAccount() .accounts({ account: tokenAccount, destination: owner, owner }) .instruction(); await ctx.sendInstruction(ix, [owner]); expect(ctx.fetchEncodedAccount(tokenAccount)).toBeNull(); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/confidential-transfer-fee.test.ts ================================================ import type { Address } from '@solana/addresses'; import { some } from '@solana/codecs'; import { type ExtensionArgs, getMintDecoder, getMintSize } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { systemClient, token2022Client } from './token-2022-test-utils'; const getConfidentialTransferFeeExts = ( feeAuthority: Address, withdrawAuthority: Address, confidentialFeeAuthority: Address, confidentialTransferAuthority: Address, elgamalPubkey: Address, ): ExtensionArgs[] => [ { __kind: 'TransferFeeConfig', newerTransferFee: { epoch: 0n, maximumFee: 1_000_000n, transferFeeBasisPoints: 100 }, olderTransferFee: { epoch: 0n, maximumFee: 0n, transferFeeBasisPoints: 0 }, transferFeeConfigAuthority: feeAuthority, withdrawWithheldAuthority: withdrawAuthority, withheldAmount: 0n, }, { __kind: 'ConfidentialTransferMint', auditorElgamalPubkey: null, authority: confidentialTransferAuthority, autoApproveNewAccounts: true, }, { __kind: 'ConfidentialTransferFee', authority: confidentialFeeAuthority, elgamalPubkey: elgamalPubkey, harvestToMintEnabled: true, withheldAmount: new Uint8Array(64), }, ]; describe('Token 2022 Program: confidentialTransferFee', () => { test('should initialize confidential transfer fee extension [initializeConfidentialTransferFee]', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mint = await ctx.createAccount(); const feeAuthority = await ctx.createFundedAccount(); const withdrawAuthority = await ctx.createFundedAccount(); const confidentialFeeAuthority = await ctx.createFundedAccount(); const confidentialTransferAuthority = await ctx.createFundedAccount(); const elgamalPubkey = await ctx.createFundedAccount(); const size = getMintSize( getConfidentialTransferFeeExts( feeAuthority, withdrawAuthority, confidentialFeeAuthority, confidentialTransferAuthority, elgamalPubkey, ), ); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(size)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space: size }) .accounts({ newAccount: mint, payer }) .instruction(); const initFeeConfigIx = await token2022Client.methods .initializeTransferFeeConfig({ maximumFee: 1_000_000, transferFeeBasisPoints: 100, transferFeeConfigAuthority: feeAuthority, withdrawWithheldAuthority: withdrawAuthority, }) .accounts({ mint }) .instruction(); const initConfidentialTransferIx = await token2022Client.methods .initializeConfidentialTransferMint({ auditorElgamalPubkey: null, authority: confidentialTransferAuthority, autoApproveNewAccounts: true, }) .accounts({ mint }) .instruction(); const initConfidentialFeeIx = await token2022Client.methods .initializeConfidentialTransferFee({ authority: confidentialFeeAuthority, withdrawWithheldAuthorityElGamalPubkey: elgamalPubkey, }) .accounts({ mint }) .instruction(); const initMintIx = await token2022Client.methods .initializeMint2({ decimals: 9, mintAuthority: payer }) .accounts({ mint }) .instruction(); await ctx.sendInstructions( [createAccountIx, initFeeConfigIx, initConfidentialTransferIx, initConfidentialFeeIx, initMintIx], [payer, mint], ); const mintData = getMintDecoder().decode(ctx.requireEncodedAccount(mint).data); expect(mintData.mintAuthority).toEqual({ __option: 'Some', value: payer }); expect(mintData.extensions).toEqual( some([ { __kind: 'TransferFeeConfig', newerTransferFee: { epoch: 0n, maximumFee: 1_000_000n, transferFeeBasisPoints: 100 }, olderTransferFee: { epoch: 0n, maximumFee: 1_000_000n, transferFeeBasisPoints: 100 }, transferFeeConfigAuthority: feeAuthority, withdrawWithheldAuthority: withdrawAuthority, withheldAmount: 0n, }, { __kind: 'ConfidentialTransferMint', auditorElgamalPubkey: { __option: 'None' }, authority: { __option: 'Some', value: confidentialTransferAuthority }, autoApproveNewAccounts: true, }, { __kind: 'ConfidentialTransferFee', authority: { __option: 'Some', value: confidentialFeeAuthority }, elgamalPubkey, harvestToMintEnabled: true, withheldAmount: Uint8Array.from({ length: 64 }, () => 0), }, ]), ); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/confidential-transfer.test.ts ================================================ import type { Address } from '@solana/addresses'; import { none, some } from '@solana/codecs'; import { type Extension, type ExtensionArgs, getMintDecoder, getMintSize } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { systemClient, token2022Client } from './token-2022-test-utils'; const getConfidentialTransferMintExt = (authority: Address): ExtensionArgs[] => [ { __kind: 'ConfidentialTransferMint', auditorElgamalPubkey: null, authority, autoApproveNewAccounts: true, }, ]; describe('Token 2022 Program: confidentialTransfer', () => { test('should initialize confidential transfer mint extension [initializeConfidentialTransferMint]', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mint = await ctx.createAccount(); const confidentialTransferAuthority = await ctx.createFundedAccount(); const size = getMintSize(getConfidentialTransferMintExt(confidentialTransferAuthority)); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(size)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space: size }) .accounts({ newAccount: mint, payer }) .instruction(); const initConfidentialTransferIx = await token2022Client.methods .initializeConfidentialTransferMint({ auditorElgamalPubkey: null, authority: confidentialTransferAuthority, autoApproveNewAccounts: true, }) .accounts({ mint }) .instruction(); const initMintIx = await token2022Client.methods .initializeMint2({ decimals: 9, mintAuthority: payer }) .accounts({ mint }) .instruction(); await ctx.sendInstructions([createAccountIx, initConfidentialTransferIx, initMintIx], [payer, mint]); const mintData = getMintDecoder().decode(ctx.requireEncodedAccount(mint).data); expect(mintData.mintAuthority).toEqual({ __option: 'Some', value: payer }); expect(mintData.extensions).toEqual( some([ { __kind: 'ConfidentialTransferMint', auditorElgamalPubkey: none(), authority: some(confidentialTransferAuthority), autoApproveNewAccounts: true, }, ]), ); }); test('should update confidential transfer mint config [updateConfidentialTransferMint]', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mint = await ctx.createAccount(); const confidentialTransferAuthority = await ctx.createFundedAccount(); const auditorElgamalPubkey = await ctx.createFundedAccount(); const size = getMintSize(getConfidentialTransferMintExt(confidentialTransferAuthority)); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(size)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space: size }) .accounts({ newAccount: mint, payer }) .instruction(); const initConfidentialTransferIx = await token2022Client.methods .initializeConfidentialTransferMint({ auditorElgamalPubkey, authority: confidentialTransferAuthority, autoApproveNewAccounts: true, }) .accounts({ mint }) .instruction(); const initMintIx = await token2022Client.methods .initializeMint2({ decimals: 9, mintAuthority: payer }) .accounts({ mint }) .instruction(); await ctx.sendInstructions([createAccountIx, initConfidentialTransferIx, initMintIx], [payer, mint]); const updateIx = await token2022Client.methods .updateConfidentialTransferMint({ auditorElgamalPubkey: null, autoApproveNewAccounts: false }) .accounts({ authority: confidentialTransferAuthority, mint }) .instruction(); await ctx.sendInstruction(updateIx, [payer, confidentialTransferAuthority]); const mintData = getMintDecoder().decode(ctx.requireEncodedAccount(mint).data); expect(mintData.extensions).toEqual( some([ { __kind: 'ConfidentialTransferMint', auditorElgamalPubkey: none(), authority: some(confidentialTransferAuthority), autoApproveNewAccounts: false, }, ]), ); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/create-native-mint.test.ts ================================================ import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { token2022Client } from './token-2022-test-utils'; describe('Token 2022 Program: createNativeMint', () => { test('should create the Token 2022 native mint', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const ix = await token2022Client.methods .createNativeMint() .accounts({ nativeMint: ctx.TOKEN_2022_NATIVE_MINT, payer }) .instruction(); await ctx.sendInstruction(ix, [payer]); const account = ctx.fetchEncodedAccount(ctx.TOKEN_2022_NATIVE_MINT); expect(account).not.toBeNull(); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/disable-cpi-guard.test.ts ================================================ import { some } from '@solana/codecs'; import { getTokenDecoder } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, createTokenAccount, token2022Client } from './token-2022-test-utils'; describe('Token 2022 Program: disableCpiGuard', () => { test('should enable/disable CPI guard on a token account', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mint = await ctx.createAccount(); const tokenAccount = await ctx.createAccount(); await createMint(ctx, payer, mint, payer); await createTokenAccount(ctx, payer, tokenAccount, mint, payer); const reallocateIx = await token2022Client.methods .reallocate({ newExtensionTypes: ['cpiGuard'] }) .accounts({ owner: payer, payer, token: tokenAccount }) .instruction(); const enableIx = await token2022Client.methods .enableCpiGuard() .accounts({ owner: payer, token: tokenAccount }) .instruction(); const disableIx = await token2022Client.methods .disableCpiGuard() .accounts({ owner: payer, token: tokenAccount }) .instruction(); await ctx.sendInstructions([reallocateIx, enableIx], [payer]); const decoder = getTokenDecoder(); const tokenDataCpiEnabled = decoder.decode(ctx.requireEncodedAccount(tokenAccount).data); expect(tokenDataCpiEnabled.extensions).toMatchObject(some([{ __kind: 'CpiGuard', lockCpi: true }])); await ctx.sendInstructions([reallocateIx, disableIx], [payer]); const tokenDataCpiDisabled = decoder.decode(ctx.requireEncodedAccount(tokenAccount).data); expect(tokenDataCpiDisabled.extensions).toMatchObject(some([{ __kind: 'CpiGuard', lockCpi: false }])); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/disable-memo-transfers.test.ts ================================================ import { some } from '@solana/codecs'; import { getTokenDecoder } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, createTokenAccount, token2022Client } from './token-2022-test-utils'; describe('Token 2022 Program: disableMemoTransfers', () => { test('should enable/disable memo transfers on a token account', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mint = await ctx.createAccount(); const tokenAccount = await ctx.createAccount(); await createMint(ctx, payer, mint, payer); await createTokenAccount(ctx, payer, tokenAccount, mint, payer); const reallocateIx = await token2022Client.methods .reallocate({ newExtensionTypes: ['memoTransfer'] }) .accounts({ owner: payer, payer, token: tokenAccount }) .instruction(); const enableIx = await token2022Client.methods .enableMemoTransfers() .accounts({ owner: payer, token: tokenAccount }) .instruction(); const disableIx = await token2022Client.methods .disableMemoTransfers() .accounts({ owner: payer, token: tokenAccount }) .instruction(); await ctx.sendInstructions([reallocateIx, enableIx], [payer]); const tokenDataEnabledMemo = getTokenDecoder().decode(ctx.requireEncodedAccount(tokenAccount).data); expect(tokenDataEnabledMemo.extensions).toMatchObject( some([{ __kind: 'MemoTransfer', requireIncomingTransferMemos: true }]), ); await ctx.sendInstructions([reallocateIx, disableIx], [payer]); const tokenDataDisabledMemo = getTokenDecoder().decode(ctx.requireEncodedAccount(tokenAccount).data); expect(tokenDataDisabledMemo.extensions).toMatchObject( some([{ __kind: 'MemoTransfer', requireIncomingTransferMemos: false }]), ); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/freeze-account.test.ts ================================================ import { AccountState, getTokenDecoder } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, createTokenAccount, token2022Client } from './token-2022-test-utils'; describe('Token 2022 Program: freezeAccount', () => { test('should freeze a token account', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const tokenAccount = await ctx.createAccount(); const freezeAuthority = await ctx.createFundedAccount(); await createMint(ctx, payer, mintAccount, payer, freezeAuthority); await createTokenAccount(ctx, payer, tokenAccount, mintAccount, payer); const freezeIx = await token2022Client.methods .freezeAccount() .accounts({ account: tokenAccount, mint: mintAccount, owner: freezeAuthority }) .instruction(); await ctx.sendInstruction(freezeIx, [freezeAuthority]); const account = ctx.requireEncodedAccount(tokenAccount); const tokenData = getTokenDecoder().decode(account.data); expect(tokenData.state).toBe(AccountState.Frozen); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/get-account-data-size.test.ts ================================================ import { getU64Decoder } from '@solana/codecs'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, TOKEN_2022_ACCOUNT_SIZE, token2022Client } from './token-2022-test-utils'; describe('Token 2022 Program: getAccountDataSize', () => { test('should return the required account size for a given mint', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); await createMint(ctx, payer, mintAccount, payer); const ix = await token2022Client.methods.getAccountDataSize().accounts({ mint: mintAccount }).instruction(); const meta = await ctx.sendInstruction(ix, [payer]); const size = getU64Decoder().decode(meta.returnData().data()); expect(size).toBe(BigInt(TOKEN_2022_ACCOUNT_SIZE)); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/group-member-pointer.test.ts ================================================ import type { Address } from '@solana/addresses'; import { type OptionOrNullable, some } from '@solana/codecs'; import { type Extension, type ExtensionArgs, getMintDecoder, getMintSize } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { systemClient, token2022Client } from './token-2022-test-utils'; const GROUP_MEMBER_POINTER_EXT = ( authority: OptionOrNullable
, memberAddress: OptionOrNullable
, ): ExtensionArgs[] => [{ __kind: 'GroupMemberPointer', authority, memberAddress }]; describe('Token 2022 Program: groupMemberPointer', () => { test('should initialize group member pointer extension [initializeGroupMemberPointer]', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mint = await ctx.createAccount(); const memberPointerAuthority = await ctx.createFundedAccount(); // GroupMemberPointer points to the mint itself const size = getMintSize(GROUP_MEMBER_POINTER_EXT(memberPointerAuthority, mint)); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(size)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space: size }) .accounts({ newAccount: mint, payer }) .instruction(); const initGroupMemberPointerIx = await token2022Client.methods .initializeGroupMemberPointer({ authority: memberPointerAuthority, memberAddress: mint }) .accounts({ mint }) .instruction(); const initMintIx = await token2022Client.methods .initializeMint2({ decimals: 9, mintAuthority: payer }) .accounts({ mint }) .instruction(); await ctx.sendInstructions([createAccountIx, initGroupMemberPointerIx, initMintIx], [payer, mint]); const mintData = getMintDecoder().decode(ctx.requireEncodedAccount(mint).data); expect(mintData.mintAuthority).toEqual({ __option: 'Some', value: payer }); expect(mintData.extensions).toEqual( some([ { __kind: 'GroupMemberPointer', authority: some(memberPointerAuthority), memberAddress: some(mint), }, ]), ); }); test('should update group member pointer address [updateGroupMemberPointer]', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mint = await ctx.createAccount(); const memberPointerAuthority = await ctx.createFundedAccount(); const newMemberAddress = await ctx.createAccount(); const size = getMintSize(GROUP_MEMBER_POINTER_EXT(memberPointerAuthority, mint)); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(size)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space: size }) .accounts({ newAccount: mint, payer }) .instruction(); const initGroupMemberPointerIx = await token2022Client.methods .initializeGroupMemberPointer({ authority: memberPointerAuthority, memberAddress: mint }) .accounts({ mint }) .instruction(); const initMintIx = await token2022Client.methods .initializeMint2({ decimals: 9, mintAuthority: payer }) .accounts({ mint }) .instruction(); await ctx.sendInstructions([createAccountIx, initGroupMemberPointerIx, initMintIx], [payer, mint]); // Update group member pointer to a new address const updateIx = await token2022Client.methods .updateGroupMemberPointer({ memberAddress: newMemberAddress }) .accounts({ groupMemberPointerAuthority: memberPointerAuthority, mint }) .signers(['groupMemberPointerAuthority']) .instruction(); await ctx.sendInstruction(updateIx, [payer, memberPointerAuthority]); const mintData = getMintDecoder().decode(ctx.requireEncodedAccount(mint).data); expect(mintData.extensions).toEqual( some([ { __kind: 'GroupMemberPointer', authority: some(memberPointerAuthority), memberAddress: some(newMemberAddress), }, ]), ); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/group-pointer.test.ts ================================================ import type { Address } from '@solana/addresses'; import { type OptionOrNullable, some } from '@solana/codecs'; import { type Extension, type ExtensionArgs, getMintDecoder, getMintSize } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { systemClient, token2022Client } from './token-2022-test-utils'; const GROUP_POINTER_EXT = ( authority: OptionOrNullable
, groupAddress: OptionOrNullable
, ): ExtensionArgs[] => [{ __kind: 'GroupPointer' as const, authority, groupAddress }]; describe('Token 2022 Program: groupPointer', () => { test('should initialize group pointer extension [initializeGroupPointer]', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mint = await ctx.createAccount(); const groupPointerAuthority = await ctx.createFundedAccount(); // GroupPointer points to the mint itself (common pattern) const size = getMintSize(GROUP_POINTER_EXT(groupPointerAuthority, mint)); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(size)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space: size }) .accounts({ newAccount: mint, payer }) .instruction(); const initGroupPointerIx = await token2022Client.methods .initializeGroupPointer({ authority: groupPointerAuthority, groupAddress: mint }) .accounts({ mint }) .instruction(); const initMintIx = await token2022Client.methods .initializeMint2({ decimals: 9, mintAuthority: payer }) .accounts({ mint }) .instruction(); await ctx.sendInstructions([createAccountIx, initGroupPointerIx, initMintIx], [payer, mint]); const mintData = getMintDecoder().decode(ctx.requireEncodedAccount(mint).data); expect(mintData.mintAuthority).toEqual({ __option: 'Some', value: payer }); expect(mintData.extensions).toEqual( some([ { __kind: 'GroupPointer', authority: some(groupPointerAuthority), groupAddress: some(mint), }, ]), ); }); test('should update group pointer address [updateGroupPointer]', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mint = await ctx.createAccount(); const groupPointerAuthority = await ctx.createFundedAccount(); const newGroupAddress = await ctx.createAccount(); const size = getMintSize(GROUP_POINTER_EXT(groupPointerAuthority, mint)); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(size)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space: size }) .accounts({ newAccount: mint, payer }) .instruction(); const initGroupPointerIx = await token2022Client.methods .initializeGroupPointer({ authority: groupPointerAuthority, groupAddress: mint }) .accounts({ mint }) .instruction(); const initMintIx = await token2022Client.methods .initializeMint2({ decimals: 9, mintAuthority: payer }) .accounts({ mint }) .instruction(); await ctx.sendInstructions([createAccountIx, initGroupPointerIx, initMintIx], [payer, mint]); // Update group pointer to a new address const updateIx = await token2022Client.methods .updateGroupPointer({ groupAddress: newGroupAddress }) .accounts({ groupPointerAuthority, mint }) .signers(['groupPointerAuthority']) .instruction(); await ctx.sendInstruction(updateIx, [payer, groupPointerAuthority]); const mintData = getMintDecoder().decode(ctx.requireEncodedAccount(mint).data); expect(mintData.extensions).toEqual( some([ { __kind: 'GroupPointer', authority: some(groupPointerAuthority), groupAddress: some(newGroupAddress) }, ]), ); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/harvest-withheld-tokens-to-mint.test.ts ================================================ import { some } from '@solana/codecs'; import { getMintDecoder } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createTokenAccountWithExtensions, createTransferFeeMint, mintTokens, token2022Client, } from './token-2022-test-utils'; const TRANSFER_FEE_AMOUNT_EXT = [{ __kind: 'TransferFeeAmount' as const, withheldAmount: 0n }]; describe('Token 2022 Program: harvestWithheldTokensToMint', () => { test('should harvest withheld tokens to mint', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const feeAuthority = await ctx.createFundedAccount(); const withdrawAuthority = await ctx.createFundedAccount(); const mint = await createTransferFeeMint(ctx, payer, feeAuthority, withdrawAuthority); const source = await createTokenAccountWithExtensions(ctx, payer, mint, payer, TRANSFER_FEE_AMOUNT_EXT); const destination = await createTokenAccountWithExtensions(ctx, payer, mint, payer, TRANSFER_FEE_AMOUNT_EXT); // Mint and transfer to generate fees await mintTokens(ctx, payer, mint, source, payer, 1_000_000); const transferIx = await token2022Client.methods .transferCheckedWithFee({ amount: 1_000_000, decimals: 9, fee: 10_000 }) .accounts({ authority: payer, destination, mint, source }) .instruction(); await ctx.sendInstruction(transferIx, [payer]); // Harvest fees from destination to mint const harvestIx = await token2022Client.methods .harvestWithheldTokensToMint({ sources: [destination] }) .accounts({ mint }) .instruction(); await ctx.sendInstruction(harvestIx, [payer]); const mintData = getMintDecoder().decode(ctx.requireEncodedAccount(mint).data); expect(mintData.extensions).toMatchObject(some([{ __kind: 'TransferFeeConfig', withheldAmount: 10_000n }])); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/initialize-account.test.ts ================================================ import { some } from '@solana/codecs'; import { AccountState, getTokenDecoder, getTokenSize } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, systemClient, token2022Client } from './token-2022-test-utils'; describe('Token 2022 Program: initializeAccount', () => { test('should initialize a token account', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const tokenAccount = await ctx.createAccount(); const owner = await ctx.createFundedAccount(); await createMint(ctx, payer, mintAccount, payer, undefined); const space = getTokenSize([{ __kind: 'MemoTransfer', requireIncomingTransferMemos: true }]); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(space)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space }) .accounts({ newAccount: tokenAccount, payer }) .instruction(); const initAccountIx = await token2022Client.methods .initializeAccount() .accounts({ account: tokenAccount, mint: mintAccount, owner }) .instruction(); const reallocateIx = await token2022Client.methods .reallocate({ newExtensionTypes: ['memoTransfer'] }) .accounts({ owner, payer, token: tokenAccount }) .signers(['owner']) .instruction(); const enableMemoTransfersIx = await token2022Client.methods .enableMemoTransfers() .accounts({ owner, token: tokenAccount }) .signers(['owner']) .instruction(); await ctx.sendInstructions( [createAccountIx, initAccountIx, reallocateIx, enableMemoTransfersIx], [payer, tokenAccount, owner], ); const accountData = ctx.requireEncodedAccount(tokenAccount).data; const tokenData = getTokenDecoder().decode(accountData); expect(tokenData.mint).toBe(mintAccount); expect(tokenData.owner).toBe(owner); expect(tokenData.amount).toBe(0n); expect(tokenData.state).toBe(AccountState.Initialized); expect(tokenData.extensions).toMatchObject( some([{ __kind: 'MemoTransfer', requireIncomingTransferMemos: true }]), ); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/initialize-account2.test.ts ================================================ import { some } from '@solana/codecs'; import { AccountState, getTokenDecoder, getTokenSize } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, systemClient, token2022Client } from './token-2022-test-utils'; describe('Token 2022 Program: initializeAccount2', () => { test('should initialize2 a token account', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const tokenAccount = await ctx.createAccount(); const owner = await ctx.createFundedAccount(); await createMint(ctx, payer, mintAccount, payer, undefined); const space = getTokenSize([{ __kind: 'MemoTransfer', requireIncomingTransferMemos: true }]); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(space)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space }) .accounts({ newAccount: tokenAccount, payer }) .instruction(); const initAccountIx = await token2022Client.methods .initializeAccount2({ owner }) .accounts({ account: tokenAccount, mint: mintAccount }) .instruction(); const reallocateIx = await token2022Client.methods .reallocate({ newExtensionTypes: ['memoTransfer'] }) .accounts({ owner, payer, token: tokenAccount }) .signers(['owner']) .instruction(); const enableMemoTransfersIx = await token2022Client.methods .enableMemoTransfers() .accounts({ owner, token: tokenAccount }) .signers(['owner']) .instruction(); await ctx.sendInstructions( [createAccountIx, initAccountIx, reallocateIx, enableMemoTransfersIx], [payer, tokenAccount, owner], ); const accountData = ctx.requireEncodedAccount(tokenAccount).data; const tokenData = getTokenDecoder().decode(accountData); expect(tokenData.mint).toBe(mintAccount); expect(tokenData.owner).toBe(owner); expect(tokenData.amount).toBe(0n); expect(tokenData.state).toBe(AccountState.Initialized); expect(tokenData.extensions).toMatchObject( some([{ __kind: 'MemoTransfer', requireIncomingTransferMemos: true }]), ); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/initialize-account3.test.ts ================================================ import { some } from '@solana/codecs'; import { AccountState, getTokenDecoder, getTokenSize } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, systemClient, token2022Client } from './token-2022-test-utils'; describe('Token 2022 Program: initializeAccount3', () => { test('should initialize3 a token account', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const tokenAccount = await ctx.createAccount(); const owner = await ctx.createFundedAccount(); await createMint(ctx, payer, mintAccount, payer, undefined); const space = getTokenSize([{ __kind: 'MemoTransfer', requireIncomingTransferMemos: true }]); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(space)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space }) .accounts({ newAccount: tokenAccount, payer }) .instruction(); const initAccountIx = await token2022Client.methods .initializeAccount3({ owner }) .accounts({ account: tokenAccount, mint: mintAccount }) .instruction(); const reallocateIx = await token2022Client.methods .reallocate({ newExtensionTypes: ['memoTransfer'] }) .accounts({ owner, payer, token: tokenAccount }) .signers(['owner']) .instruction(); const enableMemoTransfersIx = await token2022Client.methods .enableMemoTransfers() .accounts({ owner, token: tokenAccount }) .signers(['owner']) .instruction(); await ctx.sendInstructions( [createAccountIx, initAccountIx, reallocateIx, enableMemoTransfersIx], [payer, tokenAccount, owner], ); const accountData = ctx.requireEncodedAccount(tokenAccount).data; const tokenData = getTokenDecoder().decode(accountData); expect(tokenData.mint).toBe(mintAccount); expect(tokenData.owner).toBe(owner); expect(tokenData.amount).toBe(0n); expect(tokenData.state).toBe(AccountState.Initialized); expect(tokenData.extensions).toMatchObject( some([{ __kind: 'MemoTransfer', requireIncomingTransferMemos: true }]), ); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/initialize-default-account-state.test.ts ================================================ import { some } from '@solana/codecs'; import { AccountState, getMintDecoder, getMintSize } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { systemClient, token2022Client } from './token-2022-test-utils'; describe('Token 2022 Program: initializeDefaultAccountState', () => { test('should initialize default account state extension', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mint = await ctx.createAccount(); const freezeAuthority = await ctx.createFundedAccount(); const size = getMintSize([{ __kind: 'DefaultAccountState', state: AccountState.Frozen }]); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(size)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space: size }) .accounts({ newAccount: mint, payer }) .instruction(); const initDefaultStateIx = await token2022Client.methods .initializeDefaultAccountState({ state: 'frozen' }) .accounts({ mint }) .instruction(); const initMintIx = await token2022Client.methods .initializeMint2({ decimals: 9, freezeAuthority, mintAuthority: payer }) .accounts({ mint }) .instruction(); await ctx.sendInstructions([createAccountIx, initDefaultStateIx, initMintIx], [payer, mint]); const mintData = getMintDecoder().decode(ctx.requireEncodedAccount(mint).data); expect(mintData.mintAuthority).toEqual({ __option: 'Some', value: payer }); expect(mintData.freezeAuthority).toEqual({ __option: 'Some', value: freezeAuthority }); expect(mintData.extensions).toMatchObject( some([{ __kind: 'DefaultAccountState', state: AccountState.Frozen }]), ); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/initialize-immutable-owner.test.ts ================================================ import { some } from '@solana/codecs'; import { getTokenDecoder, getTokenSize } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, systemClient, token2022Client } from './token-2022-test-utils'; describe('Token 2022 Program: initializeImmutableOwner', () => { test('should initialize immutable owner extension on a token account', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mint = await ctx.createAccount(); const tokenAccount = await ctx.createAccount(); const owner = await ctx.createFundedAccount(); await createMint(ctx, payer, mint, payer); const space = getTokenSize([{ __kind: 'ImmutableOwner' }]); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(space)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space }) .accounts({ newAccount: tokenAccount, payer }) .instruction(); const initImmutableOwnerIx = await token2022Client.methods .initializeImmutableOwner() .accounts({ account: tokenAccount }) .instruction(); const initAccountIx = await token2022Client.methods .initializeAccount3({ owner }) .accounts({ account: tokenAccount, mint }) .instruction(); await ctx.sendInstructions([createAccountIx, initImmutableOwnerIx, initAccountIx], [payer, tokenAccount]); const tokenData = getTokenDecoder().decode(ctx.requireEncodedAccount(tokenAccount).data); expect(tokenData.mint).toBe(mint); expect(tokenData.owner).toBe(owner); expect(tokenData.extensions).toMatchObject(some([{ __kind: 'ImmutableOwner' }])); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/initialize-interest-bearing-mint.test.ts ================================================ import { some } from '@solana/codecs'; import { getMintDecoder, getMintSize } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { systemClient, token2022Client } from './token-2022-test-utils'; describe('Token 2022 Program: initializeInterestBearingMint', () => { test('should initialize interest bearing mint extension', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mint = await ctx.createAccount(); const rateAuthority = await ctx.createFundedAccount(); const freezeAuthority = await ctx.createFundedAccount(); const size = getMintSize([ { __kind: 'InterestBearingConfig', currentRate: 500, initializationTimestamp: 0n, lastUpdateTimestamp: 0n, preUpdateAverageRate: 0, rateAuthority, }, ]); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(size)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space: size }) .accounts({ newAccount: mint, payer }) .instruction(); const initInterestBearingIx = await token2022Client.methods .initializeInterestBearingMint({ rate: 500, rateAuthority }) .accounts({ mint }) .instruction(); const initMintIx = await token2022Client.methods .initializeMint2({ decimals: 9, freezeAuthority: freezeAuthority, mintAuthority: payer }) .accounts({ mint }) .instruction(); await ctx.sendInstructions([createAccountIx, initInterestBearingIx, initMintIx], [payer, mint]); const mintData = getMintDecoder().decode(ctx.requireEncodedAccount(mint).data); expect(mintData.mintAuthority).toEqual({ __option: 'Some', value: payer }); expect(mintData.freezeAuthority).toEqual({ __option: 'Some', value: freezeAuthority }); expect(mintData.extensions).toMatchObject( some([{ __kind: 'InterestBearingConfig', currentRate: 500, rateAuthority }]), ); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/initialize-mint-close-authority.test.ts ================================================ import { getMintDecoder, getMintSize } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { systemClient, token2022Client } from './token-2022-test-utils'; describe('Token 2022 Program: initializeMintCloseAuthority', () => { test('should initialize mint close authority extension', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mint = await ctx.createAccount(); const closeAuthority = await ctx.createAccount(); const size = getMintSize([{ __kind: 'MintCloseAuthority', closeAuthority }]); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(size)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space: size }) .accounts({ newAccount: mint, payer }) .instruction(); const initCloseAuthIx = await token2022Client.methods .initializeMintCloseAuthority({ closeAuthority }) .accounts({ mint }) .instruction(); const initMintIx = await token2022Client.methods .initializeMint2({ decimals: 9, freezeAuthority: null, mintAuthority: payer }) .accounts({ mint }) .instruction(); await ctx.sendInstructions([createAccountIx, initCloseAuthIx, initMintIx], [payer, mint]); const mintData = getMintDecoder().decode(ctx.requireEncodedAccount(mint).data); expect(mintData.mintAuthority).toEqual({ __option: 'Some', value: payer }); expect(mintData.decimals).toBe(9); expect(mintData.supply).toBe(0n); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/initialize-mint.test.ts ================================================ import { getMintDecoder } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { systemClient, TOKEN_2022_MINT_SIZE, token2022Client } from './token-2022-test-utils'; describe('Token 2022 Program: initializeMint', () => { test('should initialize a mint with default freeze authority (None)', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const mintRent = ctx.getMinimumBalanceForRentExemption(BigInt(TOKEN_2022_MINT_SIZE)); const createAccountIx = await systemClient.methods .createAccount({ lamports: mintRent, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space: TOKEN_2022_MINT_SIZE, }) .accounts({ newAccount: mintAccount, payer, }) .instruction(); const initMintIx = await token2022Client.methods .initializeMint({ decimals: 9, mintAuthority: payer }) .accounts({ mint: mintAccount }) .instruction(); await ctx.sendInstructions([createAccountIx, initMintIx], [payer, mintAccount]); const mintData = getMintDecoder().decode(ctx.requireEncodedAccount(mintAccount).data); expect(mintData.mintAuthority).toEqual({ __option: 'Some', value: payer }); expect(mintData.decimals).toBe(9); expect(mintData.supply).toBe(0n); expect(mintData.freezeAuthority).toEqual({ __option: 'None' }); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/initialize-mint2.test.ts ================================================ import { getMintDecoder } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { systemClient, TOKEN_2022_MINT_SIZE, token2022Client } from './token-2022-test-utils'; describe('Token 2022 Program: initializeMint2', () => { test('should initialize_mint2', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const freezeAuthority = await ctx.createAccount(); const mintRent = ctx.getMinimumBalanceForRentExemption(BigInt(TOKEN_2022_MINT_SIZE)); const createAccountIx = await systemClient.methods .createAccount({ lamports: mintRent, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space: TOKEN_2022_MINT_SIZE, }) .accounts({ newAccount: mintAccount, payer, }) .instruction(); const initMintIx = await token2022Client.methods .initializeMint2({ decimals: 6, freezeAuthority, mintAuthority: payer }) .accounts({ mint: mintAccount }) .instruction(); await ctx.sendInstructions([createAccountIx, initMintIx], [payer, mintAccount]); const mintData = getMintDecoder().decode(ctx.requireEncodedAccount(mintAccount).data); expect(mintData.mintAuthority).toEqual({ __option: 'Some', value: payer }); expect(mintData.decimals).toBe(6); expect(mintData.supply).toBe(0n); expect(mintData.freezeAuthority).toEqual({ __option: 'Some', value: freezeAuthority }); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/initialize-multisig.test.ts ================================================ import { getMultisigDecoder } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { systemClient, TOKEN_2022_MULTISIG_SIZE, token2022Client } from './token-2022-test-utils'; describe('Token 2022 Program: initializeMultisig', () => { test('should initialize a multisig account with signers', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const multisigAccount = await ctx.createAccount(); const signer1 = await ctx.createAccount(); const signer2 = await ctx.createAccount(); const signer3 = await ctx.createAccount(); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(TOKEN_2022_MULTISIG_SIZE)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space: TOKEN_2022_MULTISIG_SIZE, }) .accounts({ newAccount: multisigAccount, payer }) .instruction(); const initMultisigIx = await token2022Client.methods .initializeMultisig({ m: 2, signers: [signer1, signer2, signer3] }) .accounts({ multisig: multisigAccount }) .instruction(); await ctx.sendInstructions([createAccountIx, initMultisigIx], [payer, multisigAccount]); const decoder = getMultisigDecoder(); const multisigData = decoder.decode(ctx.requireEncodedAccount(multisigAccount).data); expect(multisigData.m).toBe(2); expect(multisigData.n).toBe(3); expect(multisigData.isInitialized).toBe(true); expect(multisigData.signers.slice(0, 3)).toStrictEqual([signer1, signer2, signer3]); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/initialize-multisig2.test.ts ================================================ import { getMultisigDecoder } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { systemClient, TOKEN_2022_MULTISIG_SIZE, token2022Client } from './token-2022-test-utils'; describe('Token 2022 Program: initializeMultisig2', () => { test('should initialize_multisig2 account', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const multisigAccount = await ctx.createAccount(); const signer1 = await ctx.createAccount(); const signer2 = await ctx.createAccount(); const signer3 = await ctx.createAccount(); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(TOKEN_2022_MULTISIG_SIZE)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space: TOKEN_2022_MULTISIG_SIZE, }) .accounts({ newAccount: multisigAccount, payer }) .instruction(); const initMultisigIx = await token2022Client.methods .initializeMultisig2({ m: 2, signers: [signer1, signer2, signer3] }) .accounts({ multisig: multisigAccount }) .instruction(); await ctx.sendInstructions([createAccountIx, initMultisigIx], [payer, multisigAccount]); const decoder = getMultisigDecoder(); const multisigData = decoder.decode(ctx.requireEncodedAccount(multisigAccount).data); expect(multisigData.m).toBe(2); expect(multisigData.n).toBe(3); expect(multisigData.isInitialized).toBe(true); expect(multisigData.signers.slice(0, 3)).toStrictEqual([signer1, signer2, signer3]); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/initialize-non-transferable-mint.test.ts ================================================ import { some } from '@solana/codecs'; import { getMintDecoder, getMintSize } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { systemClient, token2022Client } from './token-2022-test-utils'; describe('Token 2022 Program: initializeNonTransferableMint', () => { test('should initialize non-transferable mint extension', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mint = await ctx.createAccount(); const size = getMintSize([{ __kind: 'NonTransferable' }]); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(size)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space: size }) .accounts({ newAccount: mint, payer }) .instruction(); const initNonTransferableIx = await token2022Client.methods .initializeNonTransferableMint() .accounts({ mint }) .instruction(); const initMintIx = await token2022Client.methods .initializeMint2({ decimals: 9, mintAuthority: payer }) .accounts({ mint }) .instruction(); await ctx.sendInstructions([createAccountIx, initNonTransferableIx, initMintIx], [payer, mint]); const mintData = getMintDecoder().decode(ctx.requireEncodedAccount(mint).data); expect(mintData.mintAuthority).toEqual({ __option: 'Some', value: payer }); expect(mintData.freezeAuthority).toEqual({ __option: 'None' }); expect(mintData.supply).toBe(0n); expect(mintData.extensions).toMatchObject(some([{ __kind: 'NonTransferable' }])); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/initialize-permanent-delegate.test.ts ================================================ import { some } from '@solana/codecs'; import { getMintDecoder, getMintSize } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { systemClient, token2022Client } from './token-2022-test-utils'; describe('Token 2022 Program: initializePermanentDelegate', () => { test('should initialize permanent delegate extension', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mint = await ctx.createAccount(); const delegate = await ctx.createAccount(); const size = getMintSize([{ __kind: 'PermanentDelegate', delegate }]); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(size)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space: size }) .accounts({ newAccount: mint, payer }) .instruction(); const initPermanentDelegateIx = await token2022Client.methods .initializePermanentDelegate({ delegate }) .accounts({ mint }) .instruction(); const initMintIx = await token2022Client.methods .initializeMint2({ decimals: 9, mintAuthority: payer }) .accounts({ mint }) .instruction(); await ctx.sendInstructions([createAccountIx, initPermanentDelegateIx, initMintIx], [payer, mint]); const mintData = getMintDecoder().decode(ctx.requireEncodedAccount(mint).data); expect(mintData.mintAuthority).toEqual({ __option: 'Some', value: payer }); expect(mintData.extensions).toMatchObject(some([{ __kind: 'PermanentDelegate', delegate }])); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/metadata-pointer.test.ts ================================================ import type { Address } from '@solana/addresses'; import { some } from '@solana/codecs'; import { type ExtensionArgs, getMintDecoder, getMintSize } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { systemClient, token2022Client } from './token-2022-test-utils'; const METADATA_POINTER_EXT = (authority: Address, metadataAddress: Address): ExtensionArgs[] => [ { __kind: 'MetadataPointer', authority, metadataAddress }, ]; describe('Token 2022 Program: metadataPointer', () => { test('should initialize metadata pointer extension [initializeMetadataPointer]', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mint = await ctx.createAccount(); const metadataPointerAuthority = await ctx.createFundedAccount(); // MetadataPointer points to the mint itself const size = getMintSize(METADATA_POINTER_EXT(metadataPointerAuthority, mint)); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(size)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space: size }) .accounts({ newAccount: mint, payer }) .instruction(); const initMetadataPointerIx = await token2022Client.methods .initializeMetadataPointer({ authority: metadataPointerAuthority, metadataAddress: mint }) .accounts({ mint }) .instruction(); const initMintIx = await token2022Client.methods .initializeMint2({ decimals: 9, mintAuthority: payer }) .accounts({ mint }) .instruction(); await ctx.sendInstructions([createAccountIx, initMetadataPointerIx, initMintIx], [payer, mint]); const mintData = getMintDecoder().decode(ctx.requireEncodedAccount(mint).data); expect(mintData.mintAuthority).toEqual({ __option: 'Some', value: payer }); expect(mintData.extensions).toMatchObject( some([ { __kind: 'MetadataPointer', authority: some(metadataPointerAuthority), metadataAddress: some(mint), }, ]), ); }); test('should update metadata pointer address [updateMetadataPointer]', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mint = await ctx.createAccount(); const metadataPointerAuthority = await ctx.createFundedAccount(); const newMetadataAddress = await ctx.createAccount(); const size = getMintSize(METADATA_POINTER_EXT(metadataPointerAuthority, mint)); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(size)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space: size }) .accounts({ newAccount: mint, payer }) .instruction(); const initMetadataPointerIx = await token2022Client.methods .initializeMetadataPointer({ authority: metadataPointerAuthority, metadataAddress: mint }) .accounts({ mint }) .instruction(); const initMintIx = await token2022Client.methods .initializeMint2({ decimals: 9, mintAuthority: payer }) .accounts({ mint }) .instruction(); await ctx.sendInstructions([createAccountIx, initMetadataPointerIx, initMintIx], [payer, mint]); // Update metadata pointer to a new address const updateIx = await token2022Client.methods .updateMetadataPointer({ metadataAddress: newMetadataAddress }) .accounts({ metadataPointerAuthority, mint }) .signers(['metadataPointerAuthority']) .instruction(); await ctx.sendInstruction(updateIx, [payer, metadataPointerAuthority]); const mintData = getMintDecoder().decode(ctx.requireEncodedAccount(mint).data); expect(mintData.extensions).toMatchObject( some([{ __kind: 'MetadataPointer', metadataAddress: some(newMetadataAddress) }]), ); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/mint-to-checked.test.ts ================================================ import { getTokenDecoder } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, createTokenAccount, token2022Client } from './token-2022-test-utils'; describe('Token 2022 Program: mintToChecked', () => { test('should mint_to_checked tokens', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const tokenAccount = await ctx.createAccount(); await createMint(ctx, payer, mintAccount, payer); await createTokenAccount(ctx, payer, tokenAccount, mintAccount, payer); const ix = await token2022Client.methods .mintToChecked({ amount: 1_000_000, decimals: 9 }) .accounts({ mint: mintAccount, mintAuthority: payer, token: tokenAccount }) .instruction(); await ctx.sendInstruction(ix, [payer]); const decoder = getTokenDecoder(); const tokenData = decoder.decode(ctx.requireEncodedAccount(tokenAccount).data); expect(tokenData.amount).toBe(1_000_000n); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/mint-to.test.ts ================================================ import { getTokenDecoder } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, createTokenAccount, token2022Client } from './token-2022-test-utils'; describe('Token 2022 Program: mintTo', () => { test('should mint tokens to a token account', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const tokenAccount = await ctx.createAccount(); await createMint(ctx, payer, mintAccount, payer); await createTokenAccount(ctx, payer, tokenAccount, mintAccount, payer); const ix = await token2022Client.methods .mintTo({ amount: 1_000_000 }) .accounts({ mint: mintAccount, mintAuthority: payer, token: tokenAccount }) .instruction(); await ctx.sendInstruction(ix, [payer]); const account = ctx.requireEncodedAccount(tokenAccount); const tokenData = getTokenDecoder().decode(account.data); expect(tokenData.amount).toBe(1_000_000n); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/pausable.test.ts ================================================ import { some } from '@solana/codecs'; import { getMintDecoder, getMintSize } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { systemClient, token2022Client } from './token-2022-test-utils'; describe('Token 2022 Program: pausable', () => { test('should pause the mint [initializePausableConfig + pause]', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mint = await ctx.createAccount(); const pauseAuthority = await ctx.createFundedAccount(); const size = getMintSize([{ __kind: 'PausableConfig', authority: pauseAuthority, paused: false }]); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(size)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space: size }) .accounts({ newAccount: mint, payer }) .instruction(); const initPausableIx = await token2022Client.methods .initializePausableConfig({ authority: pauseAuthority }) .accounts({ mint }) .instruction(); const initMintIx = await token2022Client.methods .initializeMint2({ decimals: 9, mintAuthority: payer }) .accounts({ mint }) .instruction(); await ctx.sendInstructions([createAccountIx, initPausableIx, initMintIx], [payer, mint]); const mintUnpaused = getMintDecoder().decode(ctx.requireEncodedAccount(mint).data); expect(mintUnpaused.extensions).toMatchObject( some([{ __kind: 'PausableConfig', authority: some(pauseAuthority), paused: false }]), ); const pauseIx = await token2022Client.methods .pause() .accounts({ authority: pauseAuthority, mint }) .signers(['authority']) .instruction(); await ctx.sendInstruction(pauseIx, [payer, pauseAuthority]); const mintPaused = getMintDecoder().decode(ctx.requireEncodedAccount(mint).data); expect(mintPaused.extensions).toMatchObject( some([{ __kind: 'PausableConfig', authority: some(pauseAuthority), paused: true }]), ); }); test('should resume the mint [initializePausableConfig + pause + resume]', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mint = await ctx.createAccount(); const pauseAuthority = await ctx.createFundedAccount(); const size = getMintSize([{ __kind: 'PausableConfig', authority: pauseAuthority, paused: false }]); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(size)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space: size }) .accounts({ newAccount: mint, payer }) .instruction(); const initPausableIx = await token2022Client.methods .initializePausableConfig({ authority: pauseAuthority }) .accounts({ mint }) .instruction(); const initMintIx = await token2022Client.methods .initializeMint2({ decimals: 9, mintAuthority: payer }) .accounts({ mint }) .instruction(); await ctx.sendInstructions([createAccountIx, initPausableIx, initMintIx], [payer, mint]); const pauseIx = await token2022Client.methods .pause() .accounts({ authority: pauseAuthority, mint }) .signers(['authority']) .instruction(); await ctx.sendInstruction(pauseIx, [payer, pauseAuthority]); const mintDataPaused = getMintDecoder().decode(ctx.requireEncodedAccount(mint).data); expect(mintDataPaused.extensions).toMatchObject( some([{ __kind: 'PausableConfig', authority: some(pauseAuthority), paused: true }]), ); const resumeIx = await token2022Client.methods .resume() .accounts({ authority: pauseAuthority, mint }) .signers(['authority']) .instruction(); await ctx.sendInstruction(resumeIx, [payer, pauseAuthority]); const mintDataResumed = getMintDecoder().decode(ctx.requireEncodedAccount(mint).data); expect(mintDataResumed.extensions).toMatchObject( some([{ __kind: 'PausableConfig', authority: some(pauseAuthority), paused: false }]), ); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/reallocate.test.ts ================================================ import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, createTokenAccount, token2022Client } from './token-2022-test-utils'; describe('Token 2022 Program: reallocate', () => { test('should reallocate a token account to accommodate new extensions', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mint = await ctx.createAccount(); const tokenAccount = await ctx.createAccount(); await createMint(ctx, payer, mint, payer); await createTokenAccount(ctx, payer, tokenAccount, mint, payer); const balanceBefore = ctx.getBalanceOrZero(tokenAccount); const ix = await token2022Client.methods .reallocate({ newExtensionTypes: ['memoTransfer'] }) .accounts({ owner: payer, payer, token: tokenAccount }) .instruction(); await ctx.sendInstruction(ix, [payer]); const balanceAfter = ctx.getBalanceOrZero(tokenAccount); expect(balanceAfter).toBeGreaterThan(balanceBefore); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/revoke.test.ts ================================================ import { getTokenDecoder } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, createTokenAccount, mintTokens, token2022Client } from './token-2022-test-utils'; describe('Token 2022 Program: revoke', () => { test('should revoke a delegate from a token account', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const sourceAccount = await ctx.createAccount(); const delegate = await ctx.createAccount(); const decoder = getTokenDecoder(); await createMint(ctx, payer, mintAccount, payer); await createTokenAccount(ctx, payer, sourceAccount, mintAccount, payer); await mintTokens(ctx, payer, mintAccount, sourceAccount, payer, 1_000_000); const approveIx = await token2022Client.methods .approve({ amount: 500_000 }) .accounts({ delegate, owner: payer, source: sourceAccount }) .instruction(); await ctx.sendInstruction(approveIx, [payer]); const sourceDataBefore = decoder.decode(ctx.requireEncodedAccount(sourceAccount).data); expect(sourceDataBefore.delegate).toStrictEqual({ __option: 'Some', value: delegate }); expect(sourceDataBefore.delegatedAmount).toBe(500_000n); const ix = await token2022Client.methods .revoke() .accounts({ owner: payer, source: sourceAccount }) .instruction(); await ctx.sendInstruction(ix, [payer]); const sourceDataAfter = decoder.decode(ctx.requireEncodedAccount(sourceAccount).data); expect(sourceDataAfter.delegate).toStrictEqual({ __option: 'None' }); expect(sourceDataAfter.delegatedAmount).toBe(0n); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/scaled-ui-amount.test.ts ================================================ import { some } from '@solana/codecs'; import { getMintDecoder, getMintSize } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { systemClient, token2022Client } from './token-2022-test-utils'; describe('Token 2022 Program: scaledUiAmount', () => { test('should update multiplier for scaled UI amount [initializeScaledUiAmountMint + updateMultiplierScaledUiMint]', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mint = await ctx.createAccount(); const size = getMintSize([ { __kind: 'ScaledUiAmountConfig', authority: payer, multiplier: 1.0, newMultiplier: 0, newMultiplierEffectiveTimestamp: 0n, }, ]); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(size)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space: size }) .accounts({ newAccount: mint, payer }) .instruction(); const initScaledIx = await token2022Client.methods .initializeScaledUiAmountMint({ authority: payer, multiplier: 1.0 }) .accounts({ mint }) .instruction(); const initMintIx = await token2022Client.methods .initializeMint2({ decimals: 9, mintAuthority: payer }) .accounts({ mint }) .instruction(); await ctx.sendInstructions([createAccountIx, initScaledIx, initMintIx], [payer, mint]); const updateIx = await token2022Client.methods .updateMultiplierScaledUiMint({ effectiveTimestamp: 0, multiplier: 2.5 }) .accounts({ authority: payer, mint }) .instruction(); await ctx.sendInstruction(updateIx, [payer]); const mintData = getMintDecoder().decode(ctx.requireEncodedAccount(mint).data); expect(mintData.extensions).toMatchObject(some([{ __kind: 'ScaledUiAmountConfig', newMultiplier: 2.5 }])); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/set-authority.test.ts ================================================ import { getMintDecoder } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, token2022Client } from './token-2022-test-utils'; describe('Token 2022 Program: setAuthority', () => { test('should change the mint authority to a new address', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const newAuthority = await ctx.createAccount(); await createMint(ctx, payer, mintAccount, payer); const ix = await token2022Client.methods .setAuthority({ authorityType: 'mintTokens', newAuthority }) .accounts({ owned: mintAccount, owner: payer }) .instruction(); await ctx.sendInstruction(ix, [payer]); const decoder = getMintDecoder(); const mintData = decoder.decode(ctx.requireEncodedAccount(mintAccount).data); expect(mintData.mintAuthority).toStrictEqual({ __option: 'Some', value: newAuthority }); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/sync-native.test.ts ================================================ import { address } from '@solana/addresses'; import { getTokenDecoder } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { systemClient, TOKEN_2022_ACCOUNT_SIZE, token2022Client } from './token-2022-test-utils'; const TOKEN_2022_NATIVE_MINT = address('9pan9bMn5HatX4EJdBwg9VgCa7Uz5HL8N1m5D3NdXejP'); describe('Token 2022 Program: syncNative', () => { test('should sync a wrapped SOL account amount with its lamport balance', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const wrappedSolAccount = await ctx.createAccount(); // Ensure the Token 2022 native mint exists. const createNativeMintIx = await token2022Client.methods .createNativeMint() .accounts({ nativeMint: TOKEN_2022_NATIVE_MINT, payer, systemProgram: ctx.SYSTEM_PROGRAM_ADDRESS }) .instruction(); await ctx.sendInstruction(createNativeMintIx, [payer]); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(TOKEN_2022_ACCOUNT_SIZE)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space: TOKEN_2022_ACCOUNT_SIZE, }) .accounts({ newAccount: wrappedSolAccount, payer }) .instruction(); const initAccountIx = await token2022Client.methods .initializeAccount() .accounts({ account: wrappedSolAccount, mint: TOKEN_2022_NATIVE_MINT, owner: payer }) .instruction(); await ctx.sendInstructions([createAccountIx, initAccountIx], [payer, wrappedSolAccount]); const transferAmount = 1_000_000_000n; const transferIx = await systemClient.methods .transferSol({ amount: transferAmount }) .accounts({ destination: wrappedSolAccount, source: payer }) .instruction(); await ctx.sendInstruction(transferIx, [payer]); const decoder = getTokenDecoder(); const beforeSync = decoder.decode(ctx.requireEncodedAccount(wrappedSolAccount).data); expect(beforeSync.amount).toBe(0n); const syncIx = await token2022Client.methods .syncNative() .accounts({ account: wrappedSolAccount }) .instruction(); await ctx.sendInstruction(syncIx, [payer]); const afterSync = decoder.decode(ctx.requireEncodedAccount(wrappedSolAccount).data); expect(afterSync.amount).toBe(transferAmount); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/thaw-account.test.ts ================================================ import { AccountState, getTokenDecoder } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, createTokenAccount, token2022Client } from './token-2022-test-utils'; describe('Token 2022 Program: thawAccount', () => { test('should thaw a frozen account', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const tokenAccount = await ctx.createAccount(); const freezeAuthority = await ctx.createFundedAccount(); await createMint(ctx, payer, mintAccount, payer, freezeAuthority); await createTokenAccount(ctx, payer, tokenAccount, mintAccount, payer); const freezeIx = await token2022Client.methods .freezeAccount() .accounts({ account: tokenAccount, mint: mintAccount, owner: freezeAuthority }) .instruction(); await ctx.sendInstruction(freezeIx, [freezeAuthority]); const thawIx = await token2022Client.methods .thawAccount() .accounts({ account: tokenAccount, mint: mintAccount, owner: freezeAuthority }) .instruction(); await ctx.sendInstruction(thawIx, [freezeAuthority]); const account = ctx.requireEncodedAccount(tokenAccount); const tokenData = getTokenDecoder().decode(account.data); expect(tokenData.state).toBe(AccountState.Initialized); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/token-2022-test-utils.ts ================================================ import type { Address } from '@solana/addresses'; import { getMintSize, getTokenSize } from '@solana-program/token-2022'; import type { SystemProgramClient } from '../generated/system-program-idl-types'; import type { Token2022ProgramClient } from '../generated/token-2022-idl-types'; import { createTestProgramClient, SvmTestContext } from '../test-utils'; export const token2022Client = createTestProgramClient('token-2022-idl.json'); export const systemClient = createTestProgramClient('system-program-idl.json'); export const TOKEN_2022_MINT_SIZE = getMintSize(); export const TOKEN_2022_ACCOUNT_SIZE = getTokenSize(); export const TOKEN_2022_MULTISIG_SIZE = 355; // Creates basic mint without extensions. export async function createMint( ctx: SvmTestContext, payer: Address, mint: Address, mintAuthority: Address, freezeAuthority?: Address, space = TOKEN_2022_MINT_SIZE, ): Promise { const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(space)); const createMintAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space }) .accounts({ newAccount: mint, payer }) .instruction(); await ctx.sendInstruction(createMintAccountIx, [payer, mint]); const initializeMintIx = await token2022Client.methods .initializeMint({ decimals: 9, freezeAuthority: freezeAuthority ?? null, mintAuthority }) .accounts({ mint }) .instruction(); await ctx.sendInstruction(initializeMintIx, [payer]); } // Creates basic token account without extensions. export async function createTokenAccount( ctx: SvmTestContext, payer: Address, account: Address, mint: Address, owner: Address, space = TOKEN_2022_ACCOUNT_SIZE, ): Promise { const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(space)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space }) .accounts({ newAccount: account, payer }) .instruction(); const initAccountIx = await token2022Client.methods .initializeAccount() .accounts({ account, mint, owner }) .instruction(); await ctx.sendInstructions([createAccountIx, initAccountIx], [payer, account]); } // Creates a mint with TransferFeeConfig extension. export async function createTransferFeeMint( ctx: SvmTestContext, payer: Address, feeAuthority: Address, withdrawAuthority: Address, options: { maximumFee: bigint; transferFeeBasisPoints: number } = { maximumFee: 1_000_000n, transferFeeBasisPoints: 100, }, ): Promise
{ const { maximumFee, transferFeeBasisPoints } = options; const mint = await ctx.createAccount(); const size = getMintSize([ { __kind: 'TransferFeeConfig', newerTransferFee: { epoch: 0n, maximumFee, transferFeeBasisPoints }, olderTransferFee: { epoch: 0n, maximumFee: 0n, transferFeeBasisPoints: 0 }, transferFeeConfigAuthority: feeAuthority, withdrawWithheldAuthority: withdrawAuthority, withheldAmount: 0n, }, ]); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(size)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space: size }) .accounts({ newAccount: mint, payer }) .instruction(); const initFeeConfigIx = await token2022Client.methods .initializeTransferFeeConfig({ maximumFee: maximumFee, transferFeeBasisPoints: transferFeeBasisPoints, transferFeeConfigAuthority: feeAuthority, withdrawWithheldAuthority: withdrawAuthority, }) .accounts({ mint }) .instruction(); const initMintIx = await token2022Client.methods .initializeMint2({ decimals: 9, mintAuthority: payer }) .accounts({ mint }) .instruction(); await ctx.sendInstructions([createAccountIx, initFeeConfigIx, initMintIx], [payer, mint]); return mint; } // Creates a token account with given extensions. export async function createTokenAccountWithExtensions( ctx: SvmTestContext, payer: Address, mint: Address, owner: Address, extensions: NonNullable[0]>, ): Promise
{ const account = await ctx.createAccount(); const size = getTokenSize(extensions); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(size)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space: size }) .accounts({ newAccount: account, payer }) .instruction(); const initAccountIx = await token2022Client.methods .initializeAccount3({ owner }) .accounts({ account, mint }) .instruction(); await ctx.sendInstructions([createAccountIx, initAccountIx], [payer, account]); return account; } export async function mintTokens( ctx: SvmTestContext, payer: Address, mint: Address, destination: Address, mintAuthority: Address, amount: number, ): Promise { const mintIx = await token2022Client.methods .mintTo({ amount }) .accounts({ mint, mintAuthority, token: destination }) .instruction(); await ctx.sendInstruction(mintIx, [payer, mintAuthority]); } ================================================ FILE: packages/dynamic-client/test/programs/token-2022/token-group.test.ts ================================================ import type { Address } from '@solana/addresses'; import { some } from '@solana/codecs'; import { type Extension, getMintDecoder, getMintSize } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { systemClient, token2022Client } from './token-2022-test-utils'; // Create a mint with GroupPointer + TokenGroup extensions async function createGroupMint(ctx: SvmTestContext, payer: Address, groupUpdateAuthority: Address, maxSize: number) { const mint = await ctx.createAccount(); // Allocate only GroupPointer space (initializeMint2 rejects extra uninitialized TLV bytes) // initializeTokenGroup will realloc the account internally. const pointerSize = getMintSize([{ __kind: 'GroupPointer', authority: groupUpdateAuthority, groupAddress: mint }]); const fullSize = getMintSize([ { __kind: 'GroupPointer', authority: groupUpdateAuthority, groupAddress: mint }, { __kind: 'TokenGroup', maxSize, mint, size: 0, updateAuthority: some(groupUpdateAuthority) }, ]); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(fullSize)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space: pointerSize }) .accounts({ newAccount: mint, payer }) .instruction(); const initGroupPointerIx = await token2022Client.methods .initializeGroupPointer({ authority: groupUpdateAuthority, groupAddress: mint }) .accounts({ mint }) .instruction(); const initMintIx = await token2022Client.methods .initializeMint2({ decimals: 0, mintAuthority: payer }) .accounts({ mint }) .instruction(); const initTokenGroupIx = await token2022Client.methods .initializeTokenGroup({ maxSize, updateAuthority: groupUpdateAuthority }) .accounts({ group: mint, mint, mintAuthority: payer }) .instruction(); await ctx.sendInstructions([createAccountIx, initGroupPointerIx, initMintIx, initTokenGroupIx], [payer, mint]); return mint; } describe('Token 2022 Program: tokenGroup', () => { test('should initialize token group [initializeTokenGroup]', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const groupUpdateAuthority = await ctx.createFundedAccount(); const maxSize = 10; const mint = await createGroupMint(ctx, payer, groupUpdateAuthority, maxSize); const mintData = getMintDecoder().decode(ctx.requireEncodedAccount(mint).data); expect(mintData.extensions).toMatchObject( some([ { __kind: 'GroupPointer', authority: some(groupUpdateAuthority), groupAddress: some(mint) }, { __kind: 'TokenGroup', maxSize: BigInt(maxSize), size: 0n, updateAuthority: { __option: 'Some', value: groupUpdateAuthority }, }, ]), ); }); test('should update token group max size [updateTokenGroupMaxSize]', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const groupUpdateAuthority = await ctx.createFundedAccount(); const maxSize = 10; const newMaxSize = 20; const mint = await createGroupMint(ctx, payer, groupUpdateAuthority, maxSize); const updateMaxSizeIx = await token2022Client.methods .updateTokenGroupMaxSize({ maxSize: newMaxSize }) .accounts({ group: mint, updateAuthority: groupUpdateAuthority }) .instruction(); await ctx.sendInstruction(updateMaxSizeIx, [payer, groupUpdateAuthority]); const mintData = getMintDecoder().decode(ctx.requireEncodedAccount(mint).data); expect(mintData.extensions).toMatchObject( some([{ __kind: 'GroupPointer' }, { __kind: 'TokenGroup', maxSize: BigInt(newMaxSize) }]), ); }); test('should update token group update authority [updateTokenGroupUpdateAuthority]', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const groupUpdateAuthority = await ctx.createFundedAccount(); const newUpdateAuthority = await ctx.createFundedAccount(); const maxSize = 10; const mint = await createGroupMint(ctx, payer, groupUpdateAuthority, maxSize); const updateAuthorityIx = await token2022Client.methods .updateTokenGroupUpdateAuthority({ newUpdateAuthority }) .accounts({ group: mint, updateAuthority: groupUpdateAuthority }) .instruction(); await ctx.sendInstruction(updateAuthorityIx, [payer, groupUpdateAuthority]); const mintData = getMintDecoder().decode(ctx.requireEncodedAccount(mint).data); expect(mintData.extensions).toMatchObject( some([ { __kind: 'GroupPointer' }, { __kind: 'TokenGroup', updateAuthority: { __option: 'Some', value: newUpdateAuthority }, }, ]), ); }); test('should initialize token group member [initializeTokenGroupMember]', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const groupUpdateAuthority = await ctx.createFundedAccount(); const groupMint = await createGroupMint(ctx, payer, groupUpdateAuthority, 10); // const memberMint = await createMemberMint(ctx, payer, groupMint, groupUpdateAuthority); // Create a member mint with GroupMemberPointer + TokenGroupMember const memberMint = await ctx.createAccount(); // Allocate only GroupMemberPointer space; initializeTokenGroupMember will realloc. const pointerSize = getMintSize([ { __kind: 'GroupMemberPointer', authority: payer, memberAddress: memberMint }, ]); const fullSize = getMintSize([ { __kind: 'GroupMemberPointer', authority: payer, memberAddress: memberMint }, { __kind: 'TokenGroupMember', group: groupMint, memberNumber: 1, mint: memberMint }, ]); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(fullSize)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space: pointerSize }) .accounts({ newAccount: memberMint, payer }) .instruction(); const initMemberPointerIx = await token2022Client.methods .initializeGroupMemberPointer({ authority: payer, memberAddress: memberMint }) .accounts({ mint: memberMint }) .instruction(); const initMintIx = await token2022Client.methods .initializeMint2({ decimals: 0, mintAuthority: payer }) .accounts({ mint: memberMint }) .instruction(); const initTokenGroupMemberIx = await token2022Client.methods .initializeTokenGroupMember() .accounts({ group: groupMint, groupUpdateAuthority, member: memberMint, memberMint, memberMintAuthority: payer, }) .instruction(); await ctx.sendInstructions( [createAccountIx, initMemberPointerIx, initMintIx, initTokenGroupMemberIx], [payer, memberMint, groupUpdateAuthority], ); // Verify TokenGroupMember extension const memberData = getMintDecoder().decode(ctx.requireEncodedAccount(memberMint).data); expect(memberData.extensions).toEqual( some([ { __kind: 'GroupMemberPointer', authority: some(payer), memberAddress: some(memberMint) }, { __kind: 'TokenGroupMember', group: groupMint, memberNumber: 1n, mint: memberMint }, ]), ); // Verify incremented TokenGroup size const groupData = getMintDecoder().decode(ctx.requireEncodedAccount(groupMint).data); expect(groupData.extensions).toEqual( some([ { __kind: 'GroupPointer', authority: some(groupUpdateAuthority), groupAddress: some(groupMint) }, { __kind: 'TokenGroup', maxSize: 10n, mint: groupMint, size: 1n, updateAuthority: some(groupUpdateAuthority), }, ]), ); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/token-metadata.test.ts ================================================ import type { Address } from '@solana/addresses'; import { some } from '@solana/codecs'; import { type Extension, getMintDecoder, getMintSize } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { systemClient, token2022Client } from './token-2022-test-utils'; // Create a mint with MetadataPointer + TokenMetadata extensions async function createMintWithMetadata( ctx: SvmTestContext, payer: Address, updateAuthority: Address, metadata: { name: string; symbol: string; uri: string }, ) { const mint = await ctx.createAccount(); // Allocate only MetadataPointer space // initializeTokenMetadata will realloc the account internally to fit the metadata. // Fund with enough lamports for the full size (pointer + metadata) so realloc succeeds. const pointerSize = getMintSize([{ __kind: 'MetadataPointer', authority: updateAuthority, metadataAddress: mint }]); const fullSize = getMintSize([ { __kind: 'MetadataPointer', authority: updateAuthority, metadataAddress: mint }, { __kind: 'TokenMetadata', additionalMetadata: new Map(), mint, name: metadata.name, symbol: metadata.symbol, updateAuthority, uri: metadata.uri, }, ]); // Add extra space for potential field updates (updateTokenMetadataField reallocs the account) const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(fullSize * 2)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space: pointerSize }) .accounts({ newAccount: mint, payer }) .instruction(); const initMetadataPointerIx = await token2022Client.methods .initializeMetadataPointer({ authority: updateAuthority, metadataAddress: mint }) .accounts({ mint }) .instruction(); const initMintIx = await token2022Client.methods .initializeMint2({ decimals: 9, mintAuthority: payer }) .accounts({ mint }) .instruction(); const initTokenMetadataIx = await token2022Client.methods .initializeTokenMetadata({ name: metadata.name, symbol: metadata.symbol, uri: metadata.uri }) .accounts({ metadata: mint, mint, mintAuthority: payer, updateAuthority }) .instruction(); await ctx.sendInstructions( [createAccountIx, initMetadataPointerIx, initMintIx, initTokenMetadataIx], [payer, mint], ); return mint; } describe('Token 2022 Program: tokenMetadata', () => { test('should initialize token metadata [initializeTokenMetadata]', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const updateAuthority = await ctx.createFundedAccount(); const mint = await createMintWithMetadata(ctx, payer, updateAuthority, { name: 'Test Token', symbol: 'TST', uri: 'https://example.com/metadata.json', }); const mintData = getMintDecoder().decode(ctx.requireEncodedAccount(mint).data); expect(mintData.extensions).toMatchObject( some([ { __kind: 'MetadataPointer', authority: some(updateAuthority), metadataAddress: some(mint) }, { __kind: 'TokenMetadata', name: 'Test Token', symbol: 'TST', updateAuthority: { __option: 'Some', value: updateAuthority }, uri: 'https://example.com/metadata.json', }, ]), ); }); test('should update token metadata field [updateTokenMetadataField]', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const updateAuthority = await ctx.createFundedAccount(); const mint = await createMintWithMetadata(ctx, payer, updateAuthority, { name: 'Test Token', symbol: 'TST', uri: 'https://example.com/metadata.json', }); const updateNameIx = await token2022Client.methods .updateTokenMetadataField({ field: { __kind: 'name' }, value: 'Updated Token' }) .accounts({ metadata: mint, updateAuthority }) .instruction(); const updateSymbolIx = await token2022Client.methods .updateTokenMetadataField({ field: { __kind: 'symbol' }, value: 'LOL' }) .accounts({ metadata: mint, updateAuthority }) .instruction(); const addKeyIx = await token2022Client.methods .updateTokenMetadataField({ field: { __kind: 'key', fields: ['color'] }, value: 'blue' }) .accounts({ metadata: mint, updateAuthority }) .instruction(); await ctx.sendInstructions([updateNameIx, updateSymbolIx, addKeyIx], [payer, updateAuthority]); const mintData = getMintDecoder().decode(ctx.requireEncodedAccount(mint).data); expect(mintData.extensions).toEqual( some([ { __kind: 'MetadataPointer', authority: some(updateAuthority), metadataAddress: some(mint) }, { __kind: 'TokenMetadata', additionalMetadata: new Map([['color', 'blue']]), mint, name: 'Updated Token', symbol: 'LOL', updateAuthority: some(updateAuthority), uri: 'https://example.com/metadata.json', }, ]), ); }); test('should add and remove custom metadata key [updateTokenMetadataField + removeTokenMetadataKey]', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const updateAuthority = await ctx.createFundedAccount(); // Use shorter metadata so there's room for additionalMetadata in the allocated space const mint = await createMintWithMetadata(ctx, payer, updateAuthority, { name: 'T', symbol: 'T', uri: '', }); // Add a custom key-value pair const addKeyIx = await token2022Client.methods .updateTokenMetadataField({ field: { __kind: 'key', fields: ['color'] }, value: 'blue' }) .accounts({ metadata: mint, updateAuthority }) .instruction(); await ctx.sendInstruction(addKeyIx, [payer, updateAuthority]); let mintData = getMintDecoder().decode(ctx.requireEncodedAccount(mint).data); expect(mintData.extensions).toEqual( some([ { __kind: 'MetadataPointer', authority: some(updateAuthority), metadataAddress: some(mint) }, { __kind: 'TokenMetadata', additionalMetadata: new Map([['color', 'blue']]), mint, name: 'T', symbol: 'T', updateAuthority: some(updateAuthority), uri: '', }, ]), ); // Remove the custom key const removeKeyIx = await token2022Client.methods .removeTokenMetadataKey({ idempotent: false, key: 'color' }) .accounts({ metadata: mint, updateAuthority }) .instruction(); await ctx.sendInstruction(removeKeyIx, [payer, updateAuthority]); mintData = getMintDecoder().decode(ctx.requireEncodedAccount(mint).data); expect(mintData.extensions).toEqual( some([ { __kind: 'MetadataPointer', authority: some(updateAuthority), metadataAddress: some(mint) }, { __kind: 'TokenMetadata', additionalMetadata: new Map(), mint, name: 'T', symbol: 'T', updateAuthority: some(updateAuthority), uri: '', }, ]), ); }); test('should update token metadata update authority [updateTokenMetadataUpdateAuthority]', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const updateAuthority = await ctx.createFundedAccount(); const newUpdateAuthority = await ctx.createFundedAccount(); const mint = await createMintWithMetadata(ctx, payer, updateAuthority, { name: 'Test Token', symbol: 'TST', uri: 'https://example.com/metadata.json', }); const updateAuthorityIx = await token2022Client.methods .updateTokenMetadataUpdateAuthority({ newUpdateAuthority }) .accounts({ metadata: mint, updateAuthority }) .instruction(); await ctx.sendInstruction(updateAuthorityIx, [payer, updateAuthority]); const mintData = getMintDecoder().decode(ctx.requireEncodedAccount(mint).data); expect(mintData.extensions).toMatchObject( some([ { __kind: 'MetadataPointer' }, { __kind: 'TokenMetadata', updateAuthority: { __option: 'Some', value: newUpdateAuthority }, }, ]), ); }); test('should emit token metadata [emitTokenMetadata]', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const updateAuthority = await ctx.createFundedAccount(); const mint = await createMintWithMetadata(ctx, payer, updateAuthority, { name: 'Test Token', symbol: 'TST', uri: 'https://example.com/metadata.json', }); // emitTokenMetadata emits serialized TokenMetadata as return data // We just ensure that tx was not failed const emitIx = await token2022Client.methods.emitTokenMetadata().accounts({ metadata: mint }).instruction(); const result = await ctx.sendInstruction(emitIx, [payer]); expect(result.returnData().data()).toBeDefined(); // And verify metadata is unchanged after emit const mintData = getMintDecoder().decode(ctx.requireEncodedAccount(mint).data); expect(mintData.extensions).toMatchObject( some([{ __kind: 'MetadataPointer' }, { __kind: 'TokenMetadata', name: 'Test Token', symbol: 'TST' }]), ); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/transfer-checked.test.ts ================================================ import { getTokenDecoder } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, createTokenAccount, mintTokens, token2022Client } from './token-2022-test-utils'; describe('Token 2022 Program: transferChecked', () => { test('should transfer_checked tokens', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const sourceAccount = await ctx.createAccount(); const destinationAccount = await ctx.createAccount(); await createMint(ctx, payer, mintAccount, payer); await createTokenAccount(ctx, payer, sourceAccount, mintAccount, payer); await createTokenAccount(ctx, payer, destinationAccount, mintAccount, payer); await mintTokens(ctx, payer, mintAccount, sourceAccount, payer, 1_000_000); const ix = await token2022Client.methods .transferChecked({ amount: 400_000, decimals: 9 }) .accounts({ authority: payer, destination: destinationAccount, mint: mintAccount, source: sourceAccount }) .instruction(); await ctx.sendInstruction(ix, [payer]); const decoder = getTokenDecoder(); const sourceData = decoder.decode(ctx.requireEncodedAccount(sourceAccount).data); const destData = decoder.decode(ctx.requireEncodedAccount(destinationAccount).data); expect(sourceData.amount).toBe(600_000n); expect(destData.amount).toBe(400_000n); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/transfer-fee.test.ts ================================================ import { some } from '@solana/codecs'; import { getMintDecoder, getMintSize, getTokenDecoder } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createTokenAccountWithExtensions, createTransferFeeMint, mintTokens, systemClient, token2022Client, } from './token-2022-test-utils'; const TRANSFER_FEE_AMOUNT_EXT = [{ __kind: 'TransferFeeAmount' as const, withheldAmount: 0n }]; describe('Token 2022 Program: transferFee', () => { test('should initialize transfer fee config extension [initializeTransferFeeConfig]', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mint = await ctx.createAccount(); const feeAuthority = await ctx.createFundedAccount(); const withdrawAuthority = await ctx.createFundedAccount(); const size = getMintSize([ { __kind: 'TransferFeeConfig', newerTransferFee: { epoch: 0n, maximumFee: 1_000_000n, transferFeeBasisPoints: 100 }, olderTransferFee: { epoch: 0n, maximumFee: 0n, transferFeeBasisPoints: 0 }, transferFeeConfigAuthority: feeAuthority, withdrawWithheldAuthority: withdrawAuthority, withheldAmount: 0n, }, ]); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(size)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space: size }) .accounts({ newAccount: mint, payer }) .instruction(); const initFeeConfigIx = await token2022Client.methods .initializeTransferFeeConfig({ maximumFee: 1_000_000, transferFeeBasisPoints: 100, transferFeeConfigAuthority: feeAuthority, withdrawWithheldAuthority: withdrawAuthority, }) .accounts({ mint }) .instruction(); const initMintIx = await token2022Client.methods .initializeMint2({ decimals: 9, freezeAuthority: null, mintAuthority: payer }) .accounts({ mint }) .instruction(); await ctx.sendInstructions([createAccountIx, initFeeConfigIx, initMintIx], [payer, mint]); const mintData = getMintDecoder().decode(ctx.requireEncodedAccount(mint).data); expect(mintData.mintAuthority).toEqual({ __option: 'Some', value: payer }); expect(mintData.extensions).toMatchObject( some([ { __kind: 'TransferFeeConfig', transferFeeConfigAuthority: feeAuthority, withdrawWithheldAuthority: withdrawAuthority, }, ]), ); }); test('should transfer tokens with fee [transferCheckedWithFee]', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const feeAuthority = await ctx.createFundedAccount(); const withdrawAuthority = await ctx.createFundedAccount(); // Prepare mint and accounts with Transfer fee const mint = await createTransferFeeMint(ctx, payer, feeAuthority, withdrawAuthority); const source = await createTokenAccountWithExtensions(ctx, payer, mint, payer, TRANSFER_FEE_AMOUNT_EXT); const destination = await createTokenAccountWithExtensions(ctx, payer, mint, payer, TRANSFER_FEE_AMOUNT_EXT); await mintTokens(ctx, payer, mint, source, payer, 1_000_000); // Transfer with fee: 1_000_000 * 100 / 10000 = 10_000 fee const amount = 1_000_000; const fee = 10_000; const transferIx = await token2022Client.methods .transferCheckedWithFee({ amount, decimals: 9, fee }) .accounts({ authority: payer, destination, mint, source }) .instruction(); await ctx.sendInstruction(transferIx, [payer]); const decoder = getTokenDecoder(); const sourceData = decoder.decode(ctx.requireEncodedAccount(source).data); const destData = decoder.decode(ctx.requireEncodedAccount(destination).data); expect(sourceData.amount).toBe(0n); expect(destData.amount).toBe(BigInt(amount - fee)); }); test('should set new transfer fee [setTransferFee]', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const feeAuthority = await ctx.createFundedAccount(); const withdrawAuthority = await ctx.createFundedAccount(); // Prepare mint with Transfer fee const mint = await createTransferFeeMint(ctx, payer, feeAuthority, withdrawAuthority); const setFeeIx = await token2022Client.methods .setTransferFee({ maximumFee: 2_000_000, transferFeeBasisPoints: 200 }) .accounts({ mint, transferFeeConfigAuthority: feeAuthority }) .signers(['transferFeeConfigAuthority']) .instruction(); await ctx.sendInstruction(setFeeIx, [payer, feeAuthority]); const mintData = getMintDecoder().decode(ctx.requireEncodedAccount(mint).data); expect(mintData.extensions).toMatchObject( some([ { __kind: 'TransferFeeConfig', newerTransferFee: { maximumFee: 2_000_000n, transferFeeBasisPoints: 200 }, }, ]), ); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/transfer-hook.test.ts ================================================ import type { Address } from '@solana/addresses'; import { some } from '@solana/codecs'; import { type Extension, type ExtensionArgs, getMintDecoder, getMintSize } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { systemClient, token2022Client } from './token-2022-test-utils'; const getTransferHookExt = (authority: Address, programId: Address): ExtensionArgs[] => [ { __kind: 'TransferHook', authority, programId }, ]; describe('Token 2022 Program: transferHook', () => { test('should initialize transfer hook extension [initializeTransferHook]', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mint = await ctx.createAccount(); const transferHookAuthority = await ctx.createFundedAccount(); const hookProgramId = await ctx.createAccount(); const size = getMintSize(getTransferHookExt(transferHookAuthority, hookProgramId)); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(size)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space: size }) .accounts({ newAccount: mint, payer }) .instruction(); const initTransferHookIx = await token2022Client.methods .initializeTransferHook({ authority: transferHookAuthority, programId: hookProgramId }) .accounts({ mint }) .instruction(); const initMintIx = await token2022Client.methods .initializeMint2({ decimals: 9, mintAuthority: payer }) .accounts({ mint }) .instruction(); await ctx.sendInstructions([createAccountIx, initTransferHookIx, initMintIx], [payer, mint]); const mintData = getMintDecoder().decode(ctx.requireEncodedAccount(mint).data); expect(mintData.mintAuthority).toEqual({ __option: 'Some', value: payer }); expect(mintData.extensions).toEqual( some([ { __kind: 'TransferHook', authority: transferHookAuthority, programId: hookProgramId, }, ]), ); }); test('should update transfer hook program id [updateTransferHook]', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mint = await ctx.createAccount(); const transferHookAuthority = await ctx.createFundedAccount(); const hookProgramId = await ctx.createAccount(); const newHookProgramId = await ctx.createAccount(); const size = getMintSize(getTransferHookExt(transferHookAuthority, hookProgramId)); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(size)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space: size }) .accounts({ newAccount: mint, payer }) .instruction(); const initTransferHookIx = await token2022Client.methods .initializeTransferHook({ authority: transferHookAuthority, programId: hookProgramId }) .accounts({ mint }) .instruction(); const initMintIx = await token2022Client.methods .initializeMint2({ decimals: 9, mintAuthority: payer }) .accounts({ mint }) .instruction(); await ctx.sendInstructions([createAccountIx, initTransferHookIx, initMintIx], [payer, mint]); // Update transfer hook to a new program id const updateIx = await token2022Client.methods .updateTransferHook({ programId: newHookProgramId }) .accounts({ authority: transferHookAuthority, mint }) .signers(['authority']) .instruction(); await ctx.sendInstruction(updateIx, [payer, transferHookAuthority]); const mintData = getMintDecoder().decode(ctx.requireEncodedAccount(mint).data); expect(mintData.extensions).toEqual( some([ { __kind: 'TransferHook', authority: transferHookAuthority, programId: newHookProgramId }, ]), ); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/transfer.test.ts ================================================ import { getTokenDecoder } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, createTokenAccount, mintTokens, token2022Client } from './token-2022-test-utils'; describe('Token 2022 Program: transfer', () => { test('should transfer tokens between accounts', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); const sourceAccount = await ctx.createAccount(); const destinationAccount = await ctx.createAccount(); await createMint(ctx, payer, mintAccount, payer); await createTokenAccount(ctx, payer, sourceAccount, mintAccount, payer); await createTokenAccount(ctx, payer, destinationAccount, mintAccount, payer); await mintTokens(ctx, payer, mintAccount, sourceAccount, payer, 1_000_000); const ix = await token2022Client.methods .transfer({ amount: 400_000 }) .accounts({ authority: payer, destination: destinationAccount, source: sourceAccount }) .instruction(); await ctx.sendInstruction(ix, [payer]); const decoder = getTokenDecoder(); const sourceData = decoder.decode(ctx.requireEncodedAccount(sourceAccount).data); const destData = decoder.decode(ctx.requireEncodedAccount(destinationAccount).data); expect(sourceData.amount).toBe(600_000n); expect(destData.amount).toBe(400_000n); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/ui-amount-to-amount.test.ts ================================================ import { getU64Decoder } from '@solana/codecs'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createMint, token2022Client } from './token-2022-test-utils'; describe('Token 2022 Program: uiAmountToAmount', () => { test('should convert a UI amount string to a raw token amount', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mintAccount = await ctx.createAccount(); await createMint(ctx, payer, mintAccount, payer); const amount = 1_000_000_000; const uiAmount = amount / 10 ** 9; const ix = await token2022Client.methods .uiAmountToAmount({ uiAmount: uiAmount.toString() }) .accounts({ mint: mintAccount }) .instruction(); const meta = await ctx.sendInstruction(ix, [payer]); const rawAmount = getU64Decoder().decode(meta.returnData().data()); expect(rawAmount).toBe(BigInt(amount)); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/update-default-account-state.test.ts ================================================ import { some } from '@solana/codecs'; import { AccountState, getMintDecoder, getMintSize } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { systemClient, token2022Client } from './token-2022-test-utils'; describe('Token 2022 Program: updateDefaultAccountState', () => { test('should update default account state extension', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mint = await ctx.createAccount(); const freezeAuthority = await ctx.createFundedAccount(); const size = getMintSize([{ __kind: 'DefaultAccountState', state: AccountState.Frozen }]); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(size)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space: size }) .accounts({ newAccount: mint, payer }) .instruction(); const initDefaultStateIx = await token2022Client.methods .initializeDefaultAccountState({ state: 'frozen' }) .accounts({ mint }) .instruction(); const initMintIx = await token2022Client.methods .initializeMint2({ decimals: 9, freezeAuthority, mintAuthority: payer }) .accounts({ mint }) .instruction(); await ctx.sendInstructions([createAccountIx, initDefaultStateIx, initMintIx], [payer, mint]); const mintDataBefore = getMintDecoder().decode(ctx.requireEncodedAccount(mint).data); expect(mintDataBefore.extensions).toMatchObject( some([{ __kind: 'DefaultAccountState', state: AccountState.Frozen }]), ); const updateIx = await token2022Client.methods .updateDefaultAccountState({ state: 'initialized' }) .accounts({ freezeAuthority, mint }) .signers(['freezeAuthority']) .instruction(); await ctx.sendInstruction(updateIx, [payer, freezeAuthority]); const mintData = getMintDecoder().decode(ctx.requireEncodedAccount(mint).data); expect(mintData.extensions).toMatchObject( some([{ __kind: 'DefaultAccountState', state: AccountState.Initialized }]), ); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/update-rate-interest-bearing-mint.test.ts ================================================ import { some } from '@solana/codecs'; import { getMintDecoder, getMintSize } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { systemClient, token2022Client } from './token-2022-test-utils'; describe('Token 2022 Program: updateRateInterestBearingMint', () => { test('should update interest bearing mint rate', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mint = await ctx.createAccount(); const rateAuthority = await ctx.createFundedAccount(); const size = getMintSize([ { __kind: 'InterestBearingConfig', currentRate: 500, initializationTimestamp: 0n, lastUpdateTimestamp: 0n, preUpdateAverageRate: 0, rateAuthority, }, ]); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(size)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space: size }) .accounts({ newAccount: mint, payer }) .instruction(); const initInterestBearingIx = await token2022Client.methods .initializeInterestBearingMint({ rate: 500, rateAuthority }) .accounts({ mint }) .instruction(); const initMintIx = await token2022Client.methods .initializeMint2({ decimals: 9, freezeAuthority: null, mintAuthority: payer }) .accounts({ mint }) .instruction(); await ctx.sendInstructions([createAccountIx, initInterestBearingIx, initMintIx], [payer, mint]); const updateIx = await token2022Client.methods .updateRateInterestBearingMint({ rate: 1000 }) .accounts({ mint, rateAuthority }) .signers(['rateAuthority']) .instruction(); await ctx.sendInstruction(updateIx, [payer, rateAuthority]); const mintData = getMintDecoder().decode(ctx.requireEncodedAccount(mint).data); expect(mintData.extensions).toMatchObject( some([{ __kind: 'InterestBearingConfig', currentRate: 1000, rateAuthority }]), ); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/withdraw-excess-lamports.test.ts ================================================ import { getMintSize } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { systemClient, token2022Client } from './token-2022-test-utils'; describe('Token 2022 Program: withdrawExcessLamports', () => { test('should withdraw excess lamports from a mint account', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const mint = await ctx.createAccount(); const destination = await ctx.createFundedAccount(); // Create mint WITH MintCloseAuthority (required for withdrawExcessLamports). const size = getMintSize([{ __kind: 'MintCloseAuthority', closeAuthority: payer }]); const lamports = ctx.getMinimumBalanceForRentExemption(BigInt(size)); const createAccountIx = await systemClient.methods .createAccount({ lamports, programAddress: ctx.TOKEN_2022_PROGRAM_ADDRESS, space: size }) .accounts({ newAccount: mint, payer }) .instruction(); const initCloseAuthIx = await token2022Client.methods .initializeMintCloseAuthority({ closeAuthority: payer }) .accounts({ mint }) .instruction(); const initMintIx = await token2022Client.methods .initializeMint2({ decimals: 9, freezeAuthority: null, mintAuthority: payer }) .accounts({ mint }) .instruction(); await ctx.sendInstructions([createAccountIx, initCloseAuthIx, initMintIx], [payer, mint]); // Airdrop excess lamports to the mint account. ctx.airdropToAddress(mint, 1_000_000n); const destBefore = ctx.getBalanceOrZero(destination); const ix = await token2022Client.methods .withdrawExcessLamports() .accounts({ authority: payer, destinationAccount: destination, sourceAccount: mint }) .instruction(); await ctx.sendInstruction(ix, [payer]); expect(ctx.getBalanceOrZero(destination)).toBeGreaterThan(destBefore); }); }); ================================================ FILE: packages/dynamic-client/test/programs/token-2022/withdraw-withheld-tokens.test.ts ================================================ import { getTokenDecoder } from '@solana-program/token-2022'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../test-utils'; import { createTokenAccountWithExtensions, createTransferFeeMint, mintTokens, token2022Client, } from './token-2022-test-utils'; const TRANSFER_FEE_AMOUNT_EXT = [{ __kind: 'TransferFeeAmount' as const, withheldAmount: 0n }]; describe('Token 2022 Program: withdrawWithheldTokens', () => { test('should withdraw withheld tokens from mint', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const feeAuthority = await ctx.createFundedAccount(); const withdrawAuthority = await ctx.createFundedAccount(); // Prepare mint with Transfer fee const mint = await createTransferFeeMint(ctx, payer, feeAuthority, withdrawAuthority); const source = await createTokenAccountWithExtensions(ctx, payer, mint, payer, TRANSFER_FEE_AMOUNT_EXT); const destination = await createTokenAccountWithExtensions(ctx, payer, mint, payer, TRANSFER_FEE_AMOUNT_EXT); const feeReceiver = await createTokenAccountWithExtensions(ctx, payer, mint, payer, TRANSFER_FEE_AMOUNT_EXT); // Mint and transfer to generate fees await mintTokens(ctx, payer, mint, source, payer, 1_000_000); const transferIx = await token2022Client.methods .transferCheckedWithFee({ amount: 1_000_000, decimals: 9, fee: 10_000 }) .accounts({ authority: payer, destination, mint, source }) .instruction(); await ctx.sendInstruction(transferIx, [payer]); // Harvest fees from destination to mint const harvestIx = await token2022Client.methods .harvestWithheldTokensToMint({ sources: [destination] }) .accounts({ mint }) .instruction(); await ctx.sendInstruction(harvestIx, [payer]); // Withdraw from mint to feeReceiver const withdrawIx = await token2022Client.methods .withdrawWithheldTokensFromMint() .accounts({ feeReceiver, mint, withdrawWithheldAuthority: withdrawAuthority }) .signers(['withdrawWithheldAuthority']) .instruction(); await ctx.sendInstruction(withdrawIx, [payer, withdrawAuthority]); const feeReceiverData = getTokenDecoder().decode(ctx.requireEncodedAccount(feeReceiver).data); expect(feeReceiverData.amount).toBe(10_000n); }); test('should withdraw withheld tokens from accounts', async () => { const ctx = new SvmTestContext({ defaultPrograms: true }); const payer = await ctx.createFundedAccount(); const feeAuthority = await ctx.createFundedAccount(); const withdrawAuthority = await ctx.createFundedAccount(); // Prepare mint and accounts with Transfer fee const mint = await createTransferFeeMint(ctx, payer, feeAuthority, withdrawAuthority); const source = await createTokenAccountWithExtensions(ctx, payer, mint, payer, TRANSFER_FEE_AMOUNT_EXT); const destination = await createTokenAccountWithExtensions(ctx, payer, mint, payer, TRANSFER_FEE_AMOUNT_EXT); const feeReceiver = await createTokenAccountWithExtensions(ctx, payer, mint, payer, TRANSFER_FEE_AMOUNT_EXT); // Mint and transfer to generate fees await mintTokens(ctx, payer, mint, source, payer, 1_000_000); const transferIx = await token2022Client.methods .transferCheckedWithFee({ amount: 1_000_000, decimals: 9, fee: 10_000 }) .accounts({ authority: payer, destination, mint, source }) .instruction(); await ctx.sendInstruction(transferIx, [payer]); // Withdraw directly from accounts const withdrawIx = await token2022Client.methods .withdrawWithheldTokensFromAccounts({ numTokenAccounts: 1, sources: [destination] }) .accounts({ feeReceiver, mint, withdrawWithheldAuthority: withdrawAuthority }) .signers(['withdrawWithheldAuthority']) .instruction(); await ctx.sendInstruction(withdrawIx, [payer, withdrawAuthority]); const feeReceiverData = getTokenDecoder().decode(ctx.requireEncodedAccount(feeReceiver).data); expect(feeReceiverData.amount).toBe(10_000n); }); }); ================================================ FILE: packages/dynamic-client/test/svm-test-context.ts ================================================ import { type Address, address, appendTransactionMessageInstructions, compileTransaction, createAddressWithSeed, createTransactionMessage, generateKeyPairSigner, type Instruction, type KeyPairSigner, lamports, pipe, setTransactionMessageFeePayerSigner, signTransactionWithSigners, } from '@solana/kit'; import { TOKEN_PROGRAM_ADDRESS as TOKEN_PROGRAM_ADDR } from '@solana-program/token'; import { ASSOCIATED_TOKEN_PROGRAM_ADDRESS as ASSOCIATED_TOKEN_PROGRAM_ADDR, TOKEN_2022_PROGRAM_ADDRESS as T2022_PROGRAM_ADDR, } from '@solana-program/token-2022'; import { FailedTransactionMetadata, LiteSVM, type TransactionMetadata } from 'litesvm'; /** * Encoded account data returned from SVM. */ export type EncodedAccount = { readonly data: Uint8Array; readonly executable: boolean; readonly lamports: bigint; readonly owner: Address; readonly rentEpoch?: bigint; }; /** * Configuration options for the SVM test context. */ export type SvmTestContextConfig = { /** Include standard builtins */ readonly builtins?: boolean; /** Include standard SPL programs (Token, Token-2022, ATA, etc.). Default: false. */ readonly defaultPrograms?: boolean; /** Include standard precompiles (ed25519, secp256k1). Default: false. */ readonly precompiles?: boolean; /** Include standard sysvars (clock, rent, etc.). Default: false. */ readonly sysvars?: boolean; }; /** * Test context that encapsulates LiteSVM and provides a clean Solana Kit API. * * Purpose: * - Hides LiteSVM implementation details and exposes Solana Kit types (Address, Instruction) * - Manages account lifecycle and signing internally * - Provides declarative test helpers (fundAccount, sendInstruction) * * Tests work exclusively with Address types while the context handles * keypair management and transaction building behind the scenes. * Use the config parameter to include additional programs. */ export class SvmTestContext { private readonly svm: LiteSVM; private readonly accounts: Map; private currentSlot: bigint; readonly TOKEN_2022_PROGRAM_ADDRESS: Address = T2022_PROGRAM_ADDR; readonly TOKEN_PROGRAM_ADDRESS: Address = TOKEN_PROGRAM_ADDR; readonly ASSOCIATED_TOKEN_PROGRAM_ADDRESS: Address = ASSOCIATED_TOKEN_PROGRAM_ADDR; readonly SYSTEM_PROGRAM_ADDRESS = address('11111111111111111111111111111111'); readonly SYSVAR_RENT_ADDRESS = address('SysvarRent111111111111111111111111111111111'); readonly SYSVAR_INSTRUCTIONS_ADDRESS = address('Sysvar1nstructions1111111111111111111111111'); readonly BPF_LOADER_UPGRADEABLE = address('BPFLoaderUpgradeab1e11111111111111111111111'); readonly TOKEN_2022_NATIVE_MINT = address('9pan9bMn5HatX4EJdBwg9VgCa7Uz5HL8N1m5D3NdXejP'); constructor(config: SvmTestContextConfig = {}) { let svm = new LiteSVM(); if (config.defaultPrograms) { svm = svm.withDefaultPrograms(); } if (config.precompiles) { svm = svm.withPrecompiles(); } if (config.sysvars) { svm = svm.withSysvars(); } if (config.builtins) { svm = svm.withBuiltins(); } this.svm = svm; this.accounts = new Map(); this.currentSlot = BigInt(0); } /** Creates a new keypair signer */ static generateKeypair(): Promise { return generateKeyPairSigner(); } /** Generates a new Address */ static async generateAddress(): Promise
{ const signer = await SvmTestContext.generateKeypair(); return signer.address; } /** Creates a new keypair, stores it in the context, and returns its address. */ async createAccount(): Promise
{ const signer = await generateKeyPairSigner(); this.accounts.set(signer.address, signer); return signer.address; } /** Creates an account and airdrops the given lamports to it. */ async createFundedAccount(amount: bigint = BigInt(10e9)): Promise
{ const addr = await this.createAccount(); this.svm.airdrop(addr, lamports(amount)); return addr; } /** Derives an address from base + seed + programId (createWithSeed). Does not store a keypair. */ async createAccountWithSeed(base: Address, seed: string, programId: Address): Promise
{ return await createAddressWithSeed({ baseAddress: base, programAddress: programId, seed }); } /** Airdrops lamports to an account. Account must have been created via this context. */ airdrop(account: Address, amount: bigint = BigInt(1e9)): void { this.svm.airdrop(account, lamports(amount)); } /** Airdrops lamports to any address on-chain (e.g. PDAs without stored keypairs). */ airdropToAddress(account: Address, amount: bigint = BigInt(1e9)): void { this.svm.airdrop(account, lamports(amount)); } /** * Sets account data directly on any address. * @param account - The account address to set * @param accountData - The account data including lamports, data, owner, executable */ setAccount( account: Address, accountData: { readonly data: Uint8Array; readonly executable?: boolean; readonly lamports: bigint; readonly owner: Address; }, ): void { this.svm.setAccount({ address: account, data: accountData.data, executable: accountData.executable ?? false, lamports: lamports(accountData.lamports), programAddress: accountData.owner, space: BigInt(accountData.data.length), }); } /** Returns the account's lamport balance, or null if the account is unknown to the SVM. */ getBalance(account: Address): bigint | null { const balance = this.svm.getBalance(account); return balance !== null ? BigInt(balance) : null; } /** Same as getBalance but returns 0n when the account is missing. */ getBalanceOrZero(account: Address): bigint { return this.getBalance(account) ?? BigInt(0); } /** Fetches full account data (lamports, owner, data, executable). Returns null if not found. */ fetchEncodedAccount(account: Address): EncodedAccount | null { const accountInfo = this.svm.getAccount(account); if (!accountInfo.exists) { return null; } return { data: new Uint8Array(accountInfo.data), executable: accountInfo.executable, lamports: BigInt(accountInfo.lamports), owner: accountInfo.programAddress, }; } /** Like fetchEncodedAccount but throws if the account does not exist. */ requireEncodedAccount(account: Address): EncodedAccount { const encodedAccount = this.fetchEncodedAccount(account); if (!encodedAccount) { throw new Error(`Account ${account} does not exist`); } return encodedAccount; } /** Builds, signs, and sends a transaction with a single instruction. Signers must be context-owned. */ async sendInstruction(instruction: Instruction, signers: Address[]): Promise { return await this.buildAndSend([instruction], signers); } /** Builds, signs, and sends a transaction with multiple instructions. Signers must be context-owned. */ async sendInstructions(instructions: Instruction[], signers: Address[]): Promise { return await this.buildAndSend(instructions, signers); } /** Warps the SVM to the specified slot. */ warpToSlot(slot: bigint): void { this.currentSlot = slot; this.svm.warpToSlot(slot); } /** Advances the SVM by the specified number of slots (default: 1). */ advanceSlots(count: bigint = BigInt(1)): void { this.currentSlot += count; this.svm.warpToSlot(this.currentSlot); this.svm.expireBlockhash(); } /** Loads a Solana program from a .so file. */ loadProgram(programAddress: Address, programPath: string): void { this.svm.addProgramFromFile(programAddress, programPath); } /** Calculates the minimum balance required to make an account with the given data length rent-exempt. */ getMinimumBalanceForRentExemption(dataLen: bigint): bigint { return this.svm.minimumBalanceForRentExemption(dataLen); } /** Returns the underlying LiteSVM instance for direct use when needed. Consider using the public methods instead. */ getSvm(): LiteSVM { return this.svm; } private async buildAndSend(instructions: Instruction[], signers: Address[]): Promise { if (signers.length === 0) { throw new Error('At least one signer is required'); } const keypairSigners = signers.map(addr => { const signer = this.accounts.get(addr); if (!signer) { throw new Error(`Signer ${addr} not found in context`); } return signer; }); const tx = pipe( createTransactionMessage({ version: 0 }), message => setTransactionMessageFeePayerSigner(keypairSigners[0], message), message => this.svm.setTransactionMessageLifetimeUsingLatestBlockhash(message), message => appendTransactionMessageInstructions(instructions, message), message => compileTransaction(message), ); const signedTx = await signTransactionWithSigners(keypairSigners, tx); const result = this.svm.sendTransaction(signedTx); if (result instanceof FailedTransactionMetadata) { console.error('Transaction failed, logs:\n', result.meta().prettyLogs()); throw new Error(`Transaction failed: ${result.toString()}`); } return result; } } ================================================ FILE: packages/dynamic-client/test/unit/cli/generate-program-client-types.test.ts ================================================ import { execFileSync } from 'node:child_process'; import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; import { tmpdir } from 'node:os'; import path from 'node:path'; import type { RootNode } from 'codama'; import { afterAll, describe, expect, test } from 'vitest'; import { generateClientTypes } from '../../../src/cli/commands/generate-client-types/generate-client-types'; const CLI_PATH = path.resolve('bin/cli.cjs'); function execCli(args: string[]) { try { const stdout = execFileSync('node', [CLI_PATH, ...args], { cwd: path.resolve('.'), encoding: 'utf-8', stdio: 'pipe', }); return { exitCode: 0, stderr: '', stdout }; } catch (error: unknown) { const e = error as { status: number; stderr: string; stdout: string }; return { exitCode: e.status ?? 1, stderr: e.stderr ?? '', stdout: e.stdout ?? '' }; } } describe('CLI', () => { const tmpDirs: string[] = []; afterAll(() => { for (const dir of tmpDirs) { rmSync(dir, { force: true, recursive: true }); } }); test('should print help when no arguments are provided', () => { const { stdout, exitCode } = execCli([]); expect(stdout).toContain('Usage: dynamic-client'); expect(stdout).toContain('generate-client-types '); expect(exitCode).toBe(0); }); test('should print help when --help flag is provided', () => { const { stdout, exitCode } = execCli(['--help']); expect(stdout).toContain('Usage: dynamic-client'); expect(stdout).toContain('generate-client-types '); expect(exitCode).toBe(0); }); test('should exit with code 1 for unknown commands', () => { const { stderr, exitCode } = execCli(['unknown-cmd']); expect(stderr).toContain("unknown command 'unknown-cmd'"); expect(exitCode).toBe(1); }); test('should print subcommand help for generate-client-types --help', () => { const { stdout, exitCode } = execCli(['generate-client-types', '--help']); expect(stdout).toContain('generate-client-types'); expect(stdout).toContain('codama-idl'); expect(stdout).toContain('output-dir'); expect(exitCode).toBe(0); }); test('should exit with code 1 when output dir argument is missing', () => { const { exitCode, stderr } = execCli(['generate-client-types', 'some-file.json']); expect(exitCode).toBe(1); expect(stderr).toContain("missing required argument 'output-dir'"); }); test('should exit with code 1 when IDL file does not exist', () => { const tmpDir = mkdtempSync(path.join(tmpdir(), 'cli-test-')); tmpDirs.push(tmpDir); const { exitCode, stderr } = execCli(['generate-client-types', '/nonexistent/path.json', tmpDir]); expect(exitCode).toBe(1); expect(stderr).toContain('IDL file not found'); }); test('should exit with code 1 when IDL file contains invalid JSON', () => { const tmpDir = mkdtempSync(path.join(tmpdir(), 'cli-test-')); tmpDirs.push(tmpDir); const badFile = path.join(tmpDir, 'bad.json'); writeFileSync(badFile, '{ not valid json'); const { exitCode, stderr } = execCli(['generate-client-types', badFile, tmpDir]); expect(exitCode).toBe(1); expect(stderr).toContain('not valid Codama JSON'); }); test('should read IDL and write output file for generate-client-types', () => { const idlPath = path.resolve('test/programs/idls/circular-account-refs-idl.json'); const tmpDir = mkdtempSync(path.join(tmpdir(), 'cli-test-')); tmpDirs.push(tmpDir); const { exitCode } = execCli(['generate-client-types', idlPath, tmpDir]); expect(exitCode).toBe(0); const outputPath = path.join(tmpDir, 'circular-account-refs-idl-types.ts'); const output = readFileSync(outputPath, 'utf-8'); const idl = JSON.parse(readFileSync(idlPath, 'utf-8')) as RootNode; const expected = generateClientTypes(idl); expect(output).toBe(expected); }); }); ================================================ FILE: packages/dynamic-client/test/unit/cli/program-client-types.test.ts ================================================ import type { Address, ProgramDerivedAddress } from '@solana/addresses'; import type { Instruction } from '@solana/instructions'; import type { InstructionNode, RootNode } from 'codama'; import { describe, expectTypeOf, test } from 'vitest'; import type { CreateItemAccounts, CreateItemArgs, CreateItemResolvers, ResolverFn, } from '../../programs/generated/custom-resolvers-test-idl-types'; import type { AllocateArgs, CanonicalPdaSeeds, NonCanonicalPdaSeeds, ProgramMetadataPdas, ProgramMetadataProgramClient, WriteArgs, } from '../../programs/generated/pmp-idl-types'; import type { CreateAccountAccounts, CreateAccountArgs, CreateAccountMethod, SystemMethods, SystemProgramClient, } from '../../programs/generated/system-program-idl-types'; import type { InitializeConfidentialTransferMintArgs } from '../../programs/generated/token-2022-idl-types'; describe('generated program client types', () => { describe('program client without PDAs (SystemProgramClient)', () => { test('should align with ProgramClient structure', () => { expectTypeOf().toHaveProperty('instructions'); expectTypeOf().toEqualTypeOf>(); expectTypeOf().toEqualTypeOf(); expectTypeOf().not.toHaveProperty('pdas'); expectTypeOf().toHaveProperty('programAddress'); expectTypeOf().toEqualTypeOf
(); expectTypeOf().toHaveProperty('root'); expectTypeOf().toEqualTypeOf(); }); test('should have expected method keys on SystemMethods', () => { type ExpectedKeys = | 'advanceNonceAccount' | 'allocate' | 'allocateWithSeed' | 'assign' | 'assignWithSeed' | 'authorizeNonceAccount' | 'createAccount' | 'createAccountWithSeed' | 'initializeNonceAccount' | 'transferSol' | 'transferSolWithSeed' | 'upgradeNonceAccount' | 'withdrawNonceAccount'; expectTypeOf().toEqualTypeOf(); }); test('should return MethodBuilder from method call', () => { type MethodsBuilder = ReturnType; expectTypeOf().toHaveProperty('accounts'); expectTypeOf().returns.toEqualTypeOf(); expectTypeOf().toHaveProperty('instruction'); expectTypeOf().returns.toEqualTypeOf>(); expectTypeOf().toHaveProperty('resolvers'); expectTypeOf().returns.toEqualTypeOf(); expectTypeOf().toHaveProperty('signers'); expectTypeOf().returns.toEqualTypeOf(); }); test('should have correct properties on CreateAccountArgs', () => { expectTypeOf().toHaveProperty('lamports'); expectTypeOf().toEqualTypeOf(); expectTypeOf().toHaveProperty('space'); expectTypeOf().toEqualTypeOf(); expectTypeOf().toHaveProperty('programAddress'); expectTypeOf().toEqualTypeOf
(); }); test('should have correct properties on CreateAccountAccounts', () => { expectTypeOf().toEqualTypeOf
(); expectTypeOf().toEqualTypeOf
(); }); }); describe('program client with PDAs (ProgramMetadataProgramClient)', () => { test('should align with ProgramClient structure', () => { expectTypeOf().toHaveProperty('instructions'); expectTypeOf().toHaveProperty('pdas'); expectTypeOf().toEqualTypeOf(); expectTypeOf().toHaveProperty('programAddress'); expectTypeOf().toHaveProperty('root'); }); test('should have a key for every PDA defined in the IDL', () => { type ExpectedPdaKeys = 'canonical' | 'metadata' | 'nonCanonical'; expectTypeOf().toEqualTypeOf(); type PdaFn = ProgramMetadataPdas[keyof ProgramMetadataPdas]; expectTypeOf().returns.toEqualTypeOf>(); }); test('should have correct seed properties on CanonicalPdaSeeds', () => { expectTypeOf().toHaveProperty('program'); expectTypeOf().toEqualTypeOf
(); expectTypeOf().toHaveProperty('seed'); expectTypeOf().toEqualTypeOf(); }); test('should have correct seed properties on NonCanonicalPdaSeeds', () => { expectTypeOf().toHaveProperty('program'); expectTypeOf().toEqualTypeOf
(); expectTypeOf().toHaveProperty('authority'); expectTypeOf().toEqualTypeOf
(); expectTypeOf().toHaveProperty('seed'); expectTypeOf().toEqualTypeOf(); }); }); describe('remainderOptionTypeNode optional args (pmp-idl)', () => { test('should have optional data in write args', () => { expectTypeOf().toMatchObjectType<{ data?: Uint8Array | null; offset: number }>(); }); test('should have optional seed in allocate args', () => { expectTypeOf().toMatchObjectType<{ seed?: string | null }>(); }); }); describe('zeroableOptionTypeNode optional args (token-2022)', () => { test('should have optional auditorElgamalPubkey in InitializeConfidentialTransferMintArgs', () => { expectTypeOf().toMatchObjectType<{ auditorElgamalPubkey?: Address | null; authority?: Address | null; autoApproveNewAccounts: boolean; }>(); }); }); describe('resolver types', () => { test('should have expected resolver keys on CreateItemResolvers', () => { expectTypeOf().toHaveProperty('resolveDescription'); expectTypeOf().toExtend< ResolverFn >(); expectTypeOf().toHaveProperty('resolveTags'); expectTypeOf().toExtend< ResolverFn >(); }); }); }); ================================================ FILE: packages/dynamic-client/test/unit/instruction-encoding/arguments.test.ts ================================================ import { CodamaError } from '@codama/errors'; import { address } from '@solana/addresses'; import { getU32Encoder, getU64Encoder, mergeBytes } from '@solana/codecs'; import { getInitializeInstructionDataDecoder } from '@solana-program/program-metadata'; import type { InstructionNode, RootNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { createArgumentsInputValidator, encodeInstructionArguments } from '../../../src/instruction-encoding/arguments'; import { getCodecFromBytesEncoding } from '../../../src/shared/bytes-encoding'; import { loadRoot } from '../../programs/test-utils'; function getInstruction(root: RootNode, name: string): InstructionNode { const ix = root.program.instructions.find(i => i.name === name); if (!ix) throw new Error(`Instruction ${name} not found`); return ix; } describe('Instruction encoding: encodeInstructionArguments', () => { test('should encode omitted discriminator using default numberValueNode', () => { // pmp-idl.json 'write' instruction has discriminator with defaultValue: numberValueNode(0) const root = loadRoot('pmp-idl.json'); const ix = getInstruction(root, 'write'); const encoded = encodeInstructionArguments(root, ix, { data: null, offset: 2, }); // discriminator: u8 + offset: u32 expect(encoded).toEqual(new Uint8Array([0, 2, 0, 0, 0])); }); test('should encode omitted discriminator using default bytesValueNode', () => { const root = loadRoot('example-idl.json'); const ix = getInstruction(root, 'updateOptionalInput'); const encoded = encodeInstructionArguments(root, ix, { input: 42n, optionalInput: null, }); // discriminator defaulValue from updateOptionalInput: const expectedDiscriminator = getCodecFromBytesEncoding('base16').encode('1f094566b31b79c7'); const expectedInput = getU64Encoder().encode(42n); const expectedOptionalInput = new Uint8Array([0]); expect(encoded).toEqual( mergeBytes([ expectedDiscriminator as Uint8Array, expectedInput as Uint8Array, expectedOptionalInput as Uint8Array, ]), ); }); test('should transform Uint8Array in remainderOptionTypeNode argument', () => { const root = loadRoot('pmp-idl.json'); const ix = getInstruction(root, 'write'); const testData = new Uint8Array([0xde, 0xad, 0xbe, 0xef]); const encoded = encodeInstructionArguments(root, ix, { data: testData, offset: 10, }); const expected = mergeBytes([new Uint8Array([0]), getU32Encoder().encode(10) as Uint8Array, testData]); expect(encoded).toEqual(expected); }); test('should resolve definedTypeLinkNode to enumTypeNode', () => { const root = loadRoot('pmp-idl.json'); const ix = getInstruction(root, 'initialize'); // seed is a fixedSizeTypeNode(16, stringTypeNode) - needs 16-byte padded string // Enums use lowercase variant names: none=0, utf8=1, gzip=1, json=1, direct=0, etc. const encoded = encodeInstructionArguments(root, ix, { compression: 'gzip', // gzip=1 data: null, dataSource: 'url', // url=1 encoding: 'base64', // base64=3 format: 'json', // json=1 seed: 'test', // fixed 16-byte string, null-padded }); const expected = getInitializeInstructionDataDecoder().decode(encoded); expect(encoded.length).toBe(21); expect(expected.discriminator).toBe(1); expect(expected.seed).toBe('test'); expect(expected.encoding).toBe(3); expect(expected.compression).toBe(1); expect(expected.format).toBe(1); expect(expected.dataSource).toBe(1); }); test('should throw ARGUMENT_MISSING for missing required argument', () => { const root = loadRoot('pmp-idl.json'); const ix = getInstruction(root, 'write'); expect(() => encodeInstructionArguments(root, ix, {})).toThrow('Missing argument [offset] in [write].'); }); test('should throw DEFAULT_VALUE_MISSING when omitted argument has no defaultValue', () => { const root = loadRoot('pmp-idl.json'); const ix = getInstruction(root, 'write'); // Create a modified instruction where the omitted discriminator has no defaultValue. const modifiedIx: InstructionNode = { ...ix, arguments: ix.arguments.map(arg => arg.name === 'discriminator' ? { ...arg, defaultValue: undefined } : arg, ), }; expect(() => encodeInstructionArguments(root, modifiedIx, { data: null, offset: 0 })).toThrow( 'Default value is missing for argument [discriminator] in [write].', ); }); test('should throw ValidationError when omitted argument is provided', () => { const root = loadRoot('pmp-idl.json'); const ix = getInstruction(root, 'write'); // discriminator should be omitted due to strategy const validate = createArgumentsInputValidator(root, ix); expect(() => validate({ data: null, discriminator: 99, offset: 0, }), ).toThrow(CodamaError); }); test('should encode instruction with only omitted discriminator (no user args)', () => { const root = loadRoot('pmp-idl.json'); const ix = getInstruction(root, 'close'); const encoded = encodeInstructionArguments(root, ix, {}); const discriminator = 6; expect(encoded).toEqual(new Uint8Array([discriminator])); }); }); describe('Instruction validation: remaining account arguments', () => { const ADDR_1 = address('11111111111111111111111111111111'); const ADDR_2 = address('22222222222222222222222222222222222222222222'); test('should not reject remaining account args as extra keys', () => { // initializeMultisig has remainingAccounts referencing "signers" argumentValueNode // superstruct's object() rejects unknown keys, so "signers" must be stripped before validation const root = loadRoot('token-idl.json'); const ix = getInstruction(root, 'initializeMultisig'); const validate = createArgumentsInputValidator(root, ix); expect(() => validate({ m: 2, signers: [ADDR_1, ADDR_2] })).not.toThrow(); }); test('should still validate regular arguments when remaining account args are present', () => { const root = loadRoot('token-idl.json'); const ix = getInstruction(root, 'initializeMultisig'); // m is a required number argument — passing a string should fail validation const validate = createArgumentsInputValidator(root, ix); expect(() => validate({ m: 'invalid', signers: [ADDR_1] })).toThrow('Invalid argument "m"'); }); test('should not reject optional remaining account args when omitted', () => { // transfer has optional multiSigners remaining accounts const root = loadRoot('token-idl.json'); const ix = getInstruction(root, 'transfer'); const validate = createArgumentsInputValidator(root, ix); expect(() => validate({ amount: 100 })).not.toThrow(); }); test('should not reject optional remaining account args when provided', () => { const root = loadRoot('token-idl.json'); const ix = getInstruction(root, 'transfer'); const validate = createArgumentsInputValidator(root, ix); expect(() => validate({ amount: 100, multiSigners: [ADDR_1] })).not.toThrow(); }); test('should not encode remaining account args as instruction data', () => { const root = loadRoot('token-idl.json'); const ix = getInstruction(root, 'initializeMultisig'); const withSigners = encodeInstructionArguments(root, ix, { m: 2, signers: [ADDR_1, ADDR_2] }); const withoutSigners = encodeInstructionArguments(root, ix, { m: 2 }); // Remaining account args should not affect encoded data expect(withSigners).toEqual(withoutSigners); }); }); ================================================ FILE: packages/dynamic-client/test/unit/instruction-encoding/create-account-meta.test.ts ================================================ import { address } from '@solana/addresses'; import { AccountRole } from '@solana/instructions'; import type { InstructionNode, RootNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { createAccountMeta } from '../../../src/instruction-encoding/accounts/create-account-meta'; import { loadRoot } from '../../programs/test-utils'; const ADDR_1 = address('11111111111111111111111111111111'); const ADDR_2 = address('22222222222222222222222222222222222222222222'); const ADDR_3 = address('33333333333333333333333333333333333333333333'); const MULTISIG_ADDR = address('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'); describe('createAccountMeta: remaining accounts', () => { test('should append remaining accounts from argumentsInput', async () => { // initializeMultisig has remainingAccounts: [{ value: argumentValueNode("signers") }] // It has 2 regular accounts: multisig (user-provided) + rent (default: SysvarRent) const root = loadRoot('token-idl.json'); const ix = getInstruction(root, 'initializeMultisig'); const result = await createAccountMeta( root, ix, { m: 2, signers: [ADDR_1, ADDR_2, ADDR_3] }, { multisig: MULTISIG_ADDR }, ); // 2 regular accounts (multisig + rent) + 3 remaining accounts expect(result).toHaveLength(5); const remainingAccounts = result.slice(2); expect(remainingAccounts[0]).toEqual({ address: ADDR_1, role: AccountRole.READONLY }); expect(remainingAccounts[1]).toEqual({ address: ADDR_2, role: AccountRole.READONLY }); expect(remainingAccounts[2]).toEqual({ address: ADDR_3, role: AccountRole.READONLY }); }); test('should use READONLY_SIGNER role when isSigner is true', async () => { // transfer has remainingAccounts: [{ value: argumentValueNode("multiSigners"), isOptional: true, isSigner: true }] // It has 3 regular accounts: source, destination, authority (default: identity) const root = loadRoot('token-idl.json'); const ix = getInstruction(root, 'transfer'); const result = await createAccountMeta( root, ix, { amount: 100, multiSigners: [ADDR_1, ADDR_2] }, { authority: ADDR_3, destination: MULTISIG_ADDR, source: ADDR_3 }, ); // 3 regular accounts + 2 remaining accounts const remainingAccounts = result.slice(3); expect(remainingAccounts).toHaveLength(2); expect(remainingAccounts[0]).toEqual({ address: ADDR_1, role: AccountRole.READONLY_SIGNER }); expect(remainingAccounts[1]).toEqual({ address: ADDR_2, role: AccountRole.READONLY_SIGNER }); }); test('should skip optional remaining accounts when not provided', async () => { // transfer's multiSigners is optional — omitting it should produce no extra accounts const root = loadRoot('token-idl.json'); const ix = getInstruction(root, 'transfer'); const result = await createAccountMeta( root, ix, { amount: 100 }, { authority: ADDR_1, destination: MULTISIG_ADDR, source: ADDR_3 }, ); // Only 3 regular accounts, no remaining expect(result).toHaveLength(3); }); test('should append empty array as no remaining accounts', async () => { const root = loadRoot('token-idl.json'); const ix = getInstruction(root, 'initializeMultisig'); const result = await createAccountMeta(root, ix, { m: 1, signers: [] }, { multisig: MULTISIG_ADDR }); // 2 regular accounts (multisig + rent), no remaining expect(result).toHaveLength(2); }); test('should return no remaining accounts when instruction has none defined', async () => { // initializeMint has no remainingAccounts const root = loadRoot('token-idl.json'); const ix = getInstruction(root, 'initializeMint'); const result = await createAccountMeta( root, ix, { decimals: 9, freezeAuthority: null, mintAuthority: ADDR_1 }, { mint: MULTISIG_ADDR }, ); // Should only have regular accounts (mint + rent sysvar) expect(result).toHaveLength(2); }); test('should throw when remaining account argument is not an array', async () => { const root = loadRoot('token-idl.json'); const ix = getInstruction(root, 'initializeMultisig'); await expect( createAccountMeta(root, ix, { m: 2, signers: ADDR_1 }, { multisig: MULTISIG_ADDR }), ).rejects.toThrow( 'Invalid argument input [signers]: ["11111111111111111111111111111111"]. Expected [Address[]].', ); }); test('should throw when remaining account value kind is not argumentValueNode', async () => { const root = loadRoot('token-idl.json'); const ix = getInstruction(root, 'initializeMultisig'); // Replace the argumentValueNode with an unsupported value kind const remainingAccount = ix.remainingAccounts?.[0]; const modifiedRemainingAccount = Object.assign({}, remainingAccount, { value: { kind: 'resolverValueNode', name: 'someResolver' }, }) as typeof remainingAccount; const modifiedIx: InstructionNode = Object.assign({}, ix, { remainingAccounts: [modifiedRemainingAccount], }); await expect(createAccountMeta(root, modifiedIx, { m: 2 }, { multisig: MULTISIG_ADDR })).rejects.toThrow( /Expected node of kind \[argumentValueNode\], got \[resolverValueNode\]/, ); }); test('should throw when remaining account array contains invalid element types', async () => { const root = loadRoot('token-idl.json'); const ix = getInstruction(root, 'initializeMultisig'); await expect( createAccountMeta(root, ix, { m: 2, signers: [ADDR_1, 123] }, { multisig: MULTISIG_ADDR }), ).rejects.toThrow(/Expected \[Address \| PublicKey\] for account \[signers\[1\]\]/); }); test('should throw when required remaining account argument is not provided', async () => { const root = loadRoot('token-idl.json'); const ix = getInstruction(root, 'initializeMultisig'); // signers is required: await expect( createAccountMeta(root, ix, { m: 2, signers: undefined }, { multisig: MULTISIG_ADDR }), ).rejects.toThrow(/Missing argument \[signers\]/); }); }); describe('createAccountMeta: UNSUPPORTED_OPTIONAL_ACCOUNT_STRATEGY', () => { test('should throw when optionalAccountStrategy is unsupported', async () => { const root = loadRoot('token-idl.json'); const ix = getInstruction(root, 'initializeMint'); // Create an optional account with no default value. const optionalAccount = { ...ix.accounts[0], defaultValue: undefined, isOptional: true, }; // Set an invalid optionalAccountStrategy. const modifiedIx: InstructionNode = { ...ix, accounts: [optionalAccount], // @ts-expect-error - we're intentionally passing an invalid strategy to test error handling optionalAccountStrategy: 'invalid', }; await expect(createAccountMeta(root, modifiedIx, {}, { [optionalAccount.name]: null })).rejects.toThrow( 'Unsupported optional account strategy ["invalid"] for account [mint] in [initializeMint].', ); }); }); function getInstruction(root: RootNode, name: string): InstructionNode { const ix = root.program.instructions.find(i => i.name === name); if (!ix) throw new Error(`Instruction ${name} not found`); return ix; } ================================================ FILE: packages/dynamic-client/test/unit/instruction-encoding/validators.test.ts ================================================ import type { InstructionArgumentNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { createIxArgumentsValidator } from '../../../src/instruction-encoding/validators'; describe('Validators', () => { test('should throw for unsupported TypeNode kind', () => { const fakeIxArguments = [ { name: 'testArg', type: { kind: 'fooBarTypeNode' }, }, ] as unknown as InstructionArgumentNode[]; expect(() => createIxArgumentsValidator('testInstruction', fakeIxArguments, [])).toThrow( 'Validator for TypeNode "testInstruction_testArg_0" kind: fooBarTypeNode is not implemented!', ); }); }); ================================================ FILE: packages/dynamic-client/test/unit/program-client/create-program-client.test.ts ================================================ import { CodamaError } from '@codama/errors'; import { address } from '@solana/addresses'; import { describe, expect, test } from 'vitest'; import { createProgramClient } from '../../../src'; import type { MplTokenMetadataProgramClient } from '../../programs/generated/mpl-token-metadata-idl-types'; import type { SystemProgramClient } from '../../programs/generated/system-program-idl-types'; import { createTestProgramClient, loadIdl, SvmTestContext } from '../../programs/test-utils'; describe('createProgramClient', () => { describe('methods', () => { const programClient = createTestProgramClient('system-program-idl.json'); test('should throw when accessing a non-existent instruction', () => { expect(() => programClient.methods.nonExistentMethod).toThrow(CodamaError); expect(() => programClient.methods.nonExistentMethod).toThrow( /Instruction \[nonExistentMethod\] not found in IDL/, ); }); test('should list available instructions in error message', () => { try { // eslint-disable-next-line @typescript-eslint/no-unused-expressions programClient.methods.nonExistentMethod; expect.unreachable('should have thrown'); } catch (error) { const message = (error as Error).message; expect(message).toContain('Available:'); const allInstructions = [ 'createAccount', 'assign', 'transferSol', 'createAccountWithSeed', 'advanceNonceAccount', 'withdrawNonceAccount', 'initializeNonceAccount', 'authorizeNonceAccount', 'allocate', 'allocateWithSeed', 'assignWithSeed', 'transferSolWithSeed', 'upgradeNonceAccount', ]; for (const ix of allInstructions) { expect(message).toContain(ix); } } }); test('should return a builder for a valid instruction', () => { const typedClient = createTestProgramClient('system-program-idl.json'); const builder = typedClient.methods.transferSol({ amount: 1000 }); expect(builder).toBeDefined(); expect(typeof builder.accounts).toBe('function'); expect(typeof builder.instruction).toBe('function'); }); test('should support "in" operator for existing instructions', () => { expect('transferSol' in programClient.methods).toBe(true); expect('nonExistentMethod' in programClient.methods).toBe(false); }); test('should preserve standard object semantics for prototype properties with "in" operator', () => { expect('toString' in programClient.methods).toBe(true); expect('valueOf' in programClient.methods).toBe(true); expect('constructor' in programClient.methods).toBe(true); expect('hasOwnProperty' in programClient.methods).toBe(true); }); test('should not throw when accessing standard prototype properties', () => { expect(() => programClient.methods.constructor).not.toThrow(); // eslint-disable-next-line @typescript-eslint/unbound-method expect(() => programClient.methods.hasOwnProperty).not.toThrow(); expect(programClient.methods.constructor).toBeUndefined(); // eslint-disable-next-line @typescript-eslint/unbound-method expect(programClient.methods.hasOwnProperty).toBeUndefined(); }); test('should not throw when awaited directly', async () => { // eslint-disable-next-line @typescript-eslint/await-thenable const result = await programClient.methods; expect(result).toBeDefined(); }); test('should not throw when serialized with JSON.stringify', () => { expect(() => JSON.stringify(programClient.methods)).not.toThrow(); }); }); describe('pdas', () => { const pdaClient = createTestProgramClient('mpl-token-metadata-idl.json'); test('should throw when accessing a non-existent PDA', () => { // @ts-expect-error - testing error message for non-existent PDA // eslint-disable-next-line @typescript-eslint/no-unsafe-return expect(() => pdaClient.pdas.nonExistentPda).toThrow(CodamaError); // @ts-expect-error - testing error message for non-existent PDA // eslint-disable-next-line @typescript-eslint/no-unsafe-return expect(() => pdaClient.pdas.nonExistentPda).toThrow(/PDA \[nonExistentPda\] not found in IDL/); }); test('should list available PDAs in error message', () => { // @ts-expect-error - testing error message for non-existent PDA // eslint-disable-next-line @typescript-eslint/no-unsafe-return expect(() => pdaClient.pdas.nonExistentPda).toThrow(/Available:/); }); test('should support "in" operator for existing PDAs', () => { expect('metadata' in pdaClient.pdas).toBe(true); expect('nonExistentPda' in pdaClient.pdas).toBe(false); }); test('should preserve standard object semantics for prototype properties with "in" operator', () => { expect('toString' in pdaClient.pdas).toBe(true); expect('valueOf' in pdaClient.pdas).toBe(true); expect('constructor' in pdaClient.pdas).toBe(true); expect('hasOwnProperty' in pdaClient.pdas).toBe(true); }); test('should return undefined pdas for IDL without PDAs', () => { const noPdaClient = createTestProgramClient('system-program-idl.json'); expect(noPdaClient.pdas).toBeUndefined(); }); test('should return defined pdas for IDL with PDAs', () => { expect(pdaClient.pdas).toBeDefined(); }); test('should not throw when accessing standard prototype properties', () => { expect(() => pdaClient.pdas.constructor).not.toThrow(); // eslint-disable-next-line @typescript-eslint/unbound-method expect(() => pdaClient.pdas.hasOwnProperty).not.toThrow(); expect(pdaClient.pdas.constructor).toBeUndefined(); // eslint-disable-next-line @typescript-eslint/unbound-method expect(pdaClient.pdas.hasOwnProperty).toBeUndefined(); }); test('should not throw when awaited directly', async () => { // eslint-disable-next-line @typescript-eslint/await-thenable const result = await pdaClient.pdas; expect(result).toBeDefined(); }); test('should not throw when serialized with JSON.stringify', () => { expect(() => JSON.stringify(pdaClient.pdas)).not.toThrow(); }); }); describe('programId override', () => { const OVERRIDE_ADDRESS = address('7EqQdEULxWcraVx3mXKFjc84LhCkMGZCkRuDrdXkTfBR'); test('should reflect the override in programAddress', () => { const idl = loadIdl('system-program-idl.json'); const client = createProgramClient(idl, { programId: OVERRIDE_ADDRESS }); expect(client.programAddress).toBe(OVERRIDE_ADDRESS); }); test('should use the overridden program address in built instruction', async () => { const idl = loadIdl('system-program-idl.json'); const client = createProgramClient(idl, { programId: OVERRIDE_ADDRESS }); const sourceAndDest = await SvmTestContext.generateAddress(); const ix = await client.methods .transferSol({ amount: 1000 }) .accounts({ destination: sourceAndDest, source: sourceAndDest }) .instruction(); expect(ix.programAddress).toBe(OVERRIDE_ADDRESS); }); }); }); ================================================ FILE: packages/dynamic-client/test/unit/resolvers/resolve-account-value-node-address/resolve-account-value-node-address.test.ts ================================================ import { CodamaError } from '@codama/errors'; import { describe, expect, test } from 'vitest'; import { detectCircularDependency } from '../../../../src/instruction-encoding/resolvers/resolve-account-value-node-address'; describe('detectCircularDependency', () => { test('should not throw when no circular dependency exists', () => { expect(() => detectCircularDependency('c', ['a', 'b'])).not.toThrow(); }); test('should throw AccountError when circular dependency detected', () => { expect(() => detectCircularDependency('a', ['a', 'b'])).toThrow(CodamaError); }); test('should include full resolution path in error message', () => { expect(() => detectCircularDependency('a', ['a', 'b', 'c'])).toThrow( /Circular dependency detected: \[a -> b -> c -> a\]/, ); }); test('should detect dependency later in the path', () => { expect(() => detectCircularDependency('b', ['a', 'b', 'c'])).toThrow( /Circular dependency detected: \[a -> b -> c -> b\]/, ); }); test('should not throw for empty path', () => { expect(() => detectCircularDependency('a', [])).not.toThrow(); }); }); ================================================ FILE: packages/dynamic-client/test/unit/resolvers/resolve-account-value-node-address/types.test.ts ================================================ import { describe, expectTypeOf, test } from 'vitest'; import type { ResolutionPath } from '../../../../src/instruction-encoding/resolvers'; describe('ResolutionPath', () => { test('should be a readonly array of strings', () => { expectTypeOf().toEqualTypeOf(); }); }); ================================================ FILE: packages/dynamic-client/test/unit/resolvers/resolve-conditional.test.ts ================================================ import { camelCase, type ConditionalValueNode, type InstructionAccountNode, type InstructionNode, type RootNode, } from 'codama'; import { describe, expect, test } from 'vitest'; import { resolveConditionalValueNodeCondition } from '../../../src/instruction-encoding/resolvers/resolve-conditional'; import { loadRoot } from '../../programs/test-utils'; function getInstruction(root: RootNode, name: string): InstructionNode { const ix = root.program.instructions.find(i => i.name === name); if (!ix) throw new Error(`Instruction ${name} not found`); return ix; } describe('resolveConditionalValueNodeCondition: INVARIANT_VIOLATION', () => { test('should throw when conditionalValueNode has no value and no branches', async () => { const root = loadRoot('token-idl.json'); const ix = getInstruction(root, 'transfer'); const ixAccountNode: InstructionAccountNode = ix.accounts[0]; const invalidConditional: ConditionalValueNode = { condition: { kind: 'accountValueNode', name: camelCase('source') }, kind: 'conditionalValueNode', }; await expect( resolveConditionalValueNodeCondition({ accountsInput: {}, argumentsInput: {}, conditionalValueNode: invalidConditional, ixAccountNode, ixNode: ix, resolutionPath: [], resolversInput: {}, root, }), ).rejects.toThrow( 'Internal invariant violation: [Invalid conditionalValueNode: missing value and branches for account source in transfer].', ); }); }); ================================================ FILE: packages/dynamic-client/test/unit/shared/address.test.ts ================================================ import { type Address, address } from '@solana/addresses'; import { describe, expect, expectTypeOf, test } from 'vitest'; import { type AddressInput, isConvertibleAddress, isPublicKeyLike, type PublicKeyLike, toAddress, } from '../../../src/shared/address'; import { SvmTestContext } from '../../svm-test-context'; describe('isPublicKeyLike', () => { test('should return true for objects with toBase58 method', () => { const publicKey = { toBase58: () => '11111111111111111111111111111111' }; expect(isPublicKeyLike(publicKey)).toBe(true); }); test('should narrow type to PublicKeyLike', () => { const value: unknown = { toBase58: () => '11111111111111111111111111111111' }; if (isPublicKeyLike(value)) { expectTypeOf(value).toExtend(); } }); test('should return false for plain strings', () => { expect(isPublicKeyLike('11111111111111111111111111111111')).toBe(false); }); test('should return false for null', () => { expect(isPublicKeyLike(null)).toBe(false); }); test('should return false for undefined', () => { expect(isPublicKeyLike(undefined)).toBe(false); }); test('should return false for numbers', () => { expect(isPublicKeyLike(42)).toBe(false); }); test('should return false for objects without toBase58', () => { expect(isPublicKeyLike({ toString: () => 'hello' })).toBe(false); }); test('should return false for objects where toBase58 is not a function', () => { expect(isPublicKeyLike({ toBase58: 'not-a-function' })).toBe(false); }); }); describe('toAddress', () => { const VALID_ADDRESS = '11111111111111111111111111111111'; test('should convert a string to Address', () => { const result = toAddress(VALID_ADDRESS); expect(result).toBe(VALID_ADDRESS); expectTypeOf(result).toExtend
(); }); test('should convert a PublicKeyLike to Address', () => { const publicKey = { toBase58: () => VALID_ADDRESS }; const result = toAddress(publicKey); expect(result).toBe(VALID_ADDRESS); }); test('should pass through an existing Address', () => { const addr = address(VALID_ADDRESS); const result = toAddress(addr); expect(result).toBe(VALID_ADDRESS); }); test('should throw for invalid non-string or pubkey Addresses', () => { const invalidAddresses = [42n, 42, { a: 42 }, null, undefined]; for (const input of invalidAddresses) { // @ts-expect-error testing invalid inputs expect(() => toAddress(input)).toThrow(/Cannot convert value to Address/); } }); }); describe('isConvertibleAddress', () => { test('should return true for Address', async () => { const address = await SvmTestContext.generateAddress(); expect(isConvertibleAddress(address)).toBe(true); }); test('should return true for PublicKeyLike', () => { const publicKey = { toBase58: () => '11111111111111111111111111111111' }; const result = toAddress(publicKey); expect(isConvertibleAddress(result)).toBe(true); }); test('should return true for valid base58 string', () => { const addr = '11111111111111111111111111111111'; const result = toAddress(addr); expect(isConvertibleAddress(result)).toBe(true); }); test('should return false for invalid string', () => { const addr = 'invalid_address'; expect(isConvertibleAddress(addr)).toBe(false); }); test('should return false for null and undefined', () => { [null, undefined].forEach(invalidAddr => { expect(isConvertibleAddress(invalidAddr)).toBe(false); }); }); test('should return false for invalid objects', () => { [{}, { a: 42 }].forEach(invalidAddr => { expect(isConvertibleAddress(invalidAddr)).toBe(false); }); }); }); describe('AddressInput type', () => { test('should accept Address', () => { expectTypeOf(address('11111111111111111111111111111111')).toExtend(); }); test('should accept string', () => { expectTypeOf().toExtend(); }); test('should accept PublicKeyLike', () => { expectTypeOf().toExtend(); }); }); ================================================ FILE: packages/dynamic-client/test/unit/shared/bytes-encoding.test.ts ================================================ import { describe, expect, test } from 'vitest'; import { getCodecFromBytesEncoding, isUint8Array, uint8ArrayToEncodedString } from '../../../src/shared/bytes-encoding'; describe('uint8ArrayToEncodedString', () => { const helloBytes = new Uint8Array([72, 101, 108, 108, 111]); test('should encode to base16', () => { expect(uint8ArrayToEncodedString(helloBytes, 'base16')).toBe('48656c6c6f'); }); test('should encode to base58', () => { expect(uint8ArrayToEncodedString(helloBytes, 'base58')).toBe('9Ajdvzr'); }); test('should encode to base64', () => { expect(uint8ArrayToEncodedString(helloBytes, 'base64')).toBe('SGVsbG8='); }); test('should encode to utf8', () => { expect(uint8ArrayToEncodedString(helloBytes, 'utf8')).toBe('Hello'); }); test('should handle empty bytes', () => { expect(uint8ArrayToEncodedString(new Uint8Array(), 'base16')).toBe(''); }); }); describe('getCodecFromBytesEncoding', () => { test('should return codec for base16', () => { const codec = getCodecFromBytesEncoding('base16'); expect(codec).toBeDefined(); expect(codec.encode('ff')).toEqual(new Uint8Array([255])); }); test('should return codec for base58', () => { const codec = getCodecFromBytesEncoding('base58'); expect(codec).toBeDefined(); }); test('should return codec for base64', () => { const codec = getCodecFromBytesEncoding('base64'); expect(codec).toBeDefined(); }); test('should return codec for utf8', () => { const codec = getCodecFromBytesEncoding('utf8'); expect(codec).toBeDefined(); expect(codec.encode('Hi')).toEqual(new Uint8Array([72, 105])); }); test('should throw for unsupported encoding', () => { // @ts-expect-error testing invalid input expect(() => getCodecFromBytesEncoding('rot13')).toThrow(/Unrecognized bytes encoding \[.*rot13.*\]/); }); }); describe('isUint8Array', () => { test('should return true for Uint8Array', () => { expect(isUint8Array(new Uint8Array([1, 2, 3]))).toBe(true); expect(isUint8Array(new Uint8Array())).toBe(true); }); test('should return false for regular arrays', () => { expect(isUint8Array([1, 2, 3])).toBe(false); }); test('should return false for strings', () => { expect(isUint8Array('hello')).toBe(false); }); test('should return false for null and undefined', () => { expect(isUint8Array(null)).toBe(false); expect(isUint8Array(undefined)).toBe(false); }); test('should return false for other typed arrays', () => { expect(isUint8Array(new Uint16Array([1, 2]))).toBe(false); expect(isUint8Array(new Int8Array([1, 2]))).toBe(false); }); }); ================================================ FILE: packages/dynamic-client/test/unit/shared/codecs.test.ts ================================================ import { describe, expect, test } from 'vitest'; import { getMemoizedAddressEncoder, getMemoizedBase16Codec, getMemoizedBase58Codec, getMemoizedBase64Codec, getMemoizedBooleanEncoder, getMemoizedUtf8Codec, getMemoizedUtf8Encoder, } from '../../../src/shared/codecs'; import { SvmTestContext } from '../../svm-test-context'; describe('shared codecs (memoized):', () => { test('should encode a base58 address to 32 bytes (getMemoizedAddressEncoder)', async () => { const kp = await SvmTestContext.generateKeypair(); const encoder = getMemoizedAddressEncoder(); const result = encoder.encode(kp.address); expect(result.length).toBe(32); }); test('should encode a string to utf8 bytes (getMemoizedUtf8Encoder)', () => { const encoder = getMemoizedUtf8Encoder(); expect(encoder.encode('Hello')).toEqual(new Uint8Array([72, 101, 108, 108, 111])); }); test('should encode true to a single byte (getMemoizedBooleanEncoder)', () => { const encoder = getMemoizedBooleanEncoder(); expect(encoder.encode(true)).toEqual(new Uint8Array([1])); }); test('should encode a string to utf8 bytes (getMemoizedUtf8Codec)', () => { const codec = getMemoizedUtf8Codec(); expect(codec.encode('Hi')).toEqual(new Uint8Array([72, 105])); }); test('should encode a hex string to bytes (getMemoizedBase16Codec)', () => { const codec = getMemoizedBase16Codec(); expect(codec.encode('ff')).toEqual(new Uint8Array([255])); }); test('should encode a base58 string to bytes (getMemoizedBase58Codec)', () => { const codec = getMemoizedBase58Codec(); expect(codec.encode('1')).toEqual(new Uint8Array([0])); }); test('should encode a base64 string to bytes (getMemoizedBase64Codec)', () => { const codec = getMemoizedBase64Codec(); expect(codec.encode('AQ==')).toEqual(new Uint8Array([1])); }); }); ================================================ FILE: packages/dynamic-client/test/unit/shared/types.test.ts ================================================ import type { Address } from '@solana/addresses'; import type { Instruction } from '@solana/instructions'; import { describe, expectTypeOf, test } from 'vitest'; import type { AddressInput } from '../../../src/shared/address'; import type { AccountsInput, ArgumentsInput, BuildIxFn, EitherSigners, ResolverFn, ResolversInput, } from '../../../src/shared/types'; describe('AccountsInput', () => { test('should accept partial record of string to AddressInput | null', () => { expectTypeOf().toExtend>>(); }); test('should allow null values for optional accounts', () => { expectTypeOf<{ mint: null }>().toExtend(); }); test('should allow AddressInput values', () => { expectTypeOf<{ mint: Address }>().toExtend(); }); test('should allow partial (missing keys)', () => { // eslint-disable-next-line @typescript-eslint/no-empty-object-type expectTypeOf<{}>().toExtend(); }); }); describe('ArgumentsInput', () => { test('should accept partial record of string to unknown', () => { expectTypeOf().toExtend>>(); }); test('should allow any value types', () => { expectTypeOf<{ amount: bigint; name: string }>().toExtend(); }); }); describe('EitherSigners', () => { test('should be an array of strings', () => { expectTypeOf().toEqualTypeOf(); }); }); describe('ResolverFn', () => { test('should accept arguments and accounts input and return Promise', () => { expectTypeOf().toBeFunction(); expectTypeOf().parameters.toEqualTypeOf<[ArgumentsInput, AccountsInput]>(); expectTypeOf().returns.toEqualTypeOf>(); }); }); describe('ResolversInput', () => { test('should be a record of string to ResolverFn', () => { expectTypeOf().toEqualTypeOf>(); }); }); describe('BuildIxFn', () => { test('should return a Promise of Instruction', () => { expectTypeOf().returns.toEqualTypeOf>(); }); test('should allow calling with no arguments', () => { expectTypeOf().toBeCallableWith(); }); test('should accept all four parameters', () => { expectTypeOf().toBeCallableWith({}, {}, [], {}); }); }); ================================================ FILE: packages/dynamic-client/test/unit/shared/util.test.ts ================================================ import { describe, expect, expectTypeOf, test } from 'vitest'; import { formatValueType, isObjectRecord, safeStringify } from '../../../src/shared/util'; describe('isObjectRecord', () => { test('should return true for plain objects', () => { expect(isObjectRecord({})).toBe(true); expect(isObjectRecord({ key: 'value' })).toBe(true); }); test('should narrow type to Record', () => { const value: unknown = { key: 'value' }; if (isObjectRecord(value)) { expectTypeOf(value).toExtend>(); } }); test('should return false for null', () => { expect(isObjectRecord(null)).toBe(false); }); test('should return false for arrays', () => { expect(isObjectRecord([1, 2, 3])).toBe(false); }); test('should return false for primitives', () => { expect(isObjectRecord('string')).toBe(false); expect(isObjectRecord(42)).toBe(false); expect(isObjectRecord(true)).toBe(false); expect(isObjectRecord(undefined)).toBe(false); }); test('should return false for class instances', () => { expect(isObjectRecord(new Date())).toBe(false); expect(isObjectRecord(new Map())).toBe(false); }); test('should return false for Uint8Array', () => { expect(isObjectRecord(new Uint8Array([1, 2]))).toBe(false); }); }); describe('formatValueType', () => { test('should return "null" for null', () => { expect(formatValueType(null)).toBe('null'); }); test('should return array description with length', () => { expect(formatValueType([1, 2, 3])).toBe('array (length 3)'); expect(formatValueType([])).toBe('array (length 0)'); }); test('should return Uint8Array description with length', () => { expect(formatValueType(new Uint8Array([1, 2]))).toBe('Uint8Array (length 2)'); expect(formatValueType(new Uint8Array())).toBe('Uint8Array (length 0)'); }); test('should return "object" for plain objects', () => { expect(formatValueType({ key: 'value' })).toBe('object'); }); test('should return "object" for class instances', () => { expect(formatValueType(new Date())).toBe('object'); }); test('should return typeof for primitives', () => { expect(formatValueType('hello')).toBe('string'); expect(formatValueType(42)).toBe('number'); expect(formatValueType(true)).toBe('boolean'); expect(formatValueType(undefined)).toBe('undefined'); expect(formatValueType(42n)).toBe('bigint'); }); }); describe('safeStringify', () => { test('should stringify plain objects', () => { expect(safeStringify({ a: 1 })).toBe('{"a":1}'); }); test('should stringify arrays', () => { expect(safeStringify([1, 2, 3])).toBe('[1,2,3]'); }); test('should stringify primitives', () => { expect(safeStringify('hello')).toBe('"hello"'); expect(safeStringify(42)).toBe('42'); expect(safeStringify(null)).toBe('null'); expect(safeStringify(true)).toBe('true'); }); test('should convert BigInt to string', () => { expect(safeStringify(42n)).toBe('"42"'); expect(safeStringify({ amount: 1000n })).toBe('{"amount":"1000"}'); }); test('should return non-serializable object for circular references', () => { const circular: Record = {}; circular.self = circular; expect(safeStringify(circular)).toBe('non-serializable object'); }); test('should always return a string', () => { expectTypeOf(safeStringify).returns.toBeString(); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/account-default-value/account-default-value-test-utils.ts ================================================ import { address } from '@solana/addresses'; import type { InstructionAccountNode } from 'codama'; import { instructionAccountNode, instructionNode, programNode, rootNode } from 'codama'; import { createAccountDefaultValueVisitor } from '../../../../src/instruction-encoding/visitors/account-default-value'; export const programAddress = address('11111111111111111111111111111111'); export const rootNodeMock = rootNode(programNode({ name: 'test', publicKey: programAddress })); export const ixNodeStub = instructionNode({ name: 'testInstruction' }); export const ixAccountNodeStub: InstructionAccountNode = instructionAccountNode({ isOptional: false, isSigner: false, isWritable: false, name: 'testAccount', }); export function makeVisitor(overrides?: Partial[0]>) { return createAccountDefaultValueVisitor({ accountAddressInput: undefined, accountsInput: undefined, argumentsInput: undefined, ixAccountNode: ixAccountNodeStub, ixNode: ixNodeStub, resolutionPath: [], resolversInput: undefined, root: rootNodeMock, ...overrides, }); } ================================================ FILE: packages/dynamic-client/test/unit/visitors/account-default-value/accountBumpValueNode.test.ts ================================================ import { accountBumpValueNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { makeVisitor } from './account-default-value-test-utils'; describe('account-default-value: visitAccountBumpValue', () => { test('should throw "not yet supported"', async () => { const visitor = makeVisitor(); await expect(visitor.visitAccountBumpValue(accountBumpValueNode('seed'))).rejects.toThrow( /Unsupported node kind \[accountBumpValueNode\]/, ); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/account-default-value/accountValueNode.test.ts ================================================ import { accountValueNode, instructionAccountNode, instructionNode, publicKeyValueNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../../../svm-test-context'; import { makeVisitor } from './account-default-value-test-utils'; describe('account-default-value: visitAccountValue', async () => { const refAddress = await SvmTestContext.generateAddress(); const ixNodeWithAccount = instructionNode({ accounts: [ instructionAccountNode({ isOptional: false, isSigner: false, isWritable: false, name: 'refAccount', }), ], name: 'testInstruction', }); test('should return address when user provides address in accountsInput', async () => { const visitor = makeVisitor({ accountsInput: { refAccount: refAddress }, ixNode: ixNodeWithAccount, }); const result = await visitor.visitAccountValue(accountValueNode('refAccount')); expect(result).toBe(refAddress); }); test('should return null for optional account with null input and omitted strategy', async () => { const ixNodeWithOptional = instructionNode({ accounts: [ instructionAccountNode({ isOptional: true, isSigner: false, isWritable: false, name: 'refAccount', }), ], name: 'testInstruction', optionalAccountStrategy: 'omitted', }); const visitor = makeVisitor({ accountsInput: { refAccount: null }, ixNode: ixNodeWithOptional, }); const result = await visitor.visitAccountValue(accountValueNode('refAccount')); expect(result).toBeNull(); }); test('should resolve referenced account defaultValue', async () => { const expectedDefaultAddress = await SvmTestContext.generateAddress(); const ixNodeWithDefault = instructionNode({ accounts: [ instructionAccountNode({ defaultValue: publicKeyValueNode(expectedDefaultAddress), isOptional: false, isSigner: false, isWritable: false, name: 'refAccount', }), ], name: 'testInstruction', }); const visitor = makeVisitor({ ixNode: ixNodeWithDefault }); const result = await visitor.visitAccountValue(accountValueNode('refAccount')); expect(result).toBe(expectedDefaultAddress); }); test('should throw for unknown account reference', async () => { const visitor = makeVisitor(); await expect(visitor.visitAccountValue(accountValueNode('unknown'))).rejects.toThrow( /Referenced node \[unknown\] not found in \[testInstruction\]/, ); }); test('should throw on circular dependency', async () => { const visitor = makeVisitor({ ixNode: ixNodeWithAccount, resolutionPath: ['refAccount'], }); await expect(visitor.visitAccountValue(accountValueNode('refAccount'))).rejects.toThrow( /Circular dependency detected: \[/, ); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/account-default-value/argumentValueNode.test.ts ================================================ import { argumentValueNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../../../svm-test-context'; import { makeVisitor } from './account-default-value-test-utils'; describe('account-default-value: visitArgumentValue', () => { test('should return address from argument value', async () => { const addr = await SvmTestContext.generateAddress(); const visitor = makeVisitor({ argumentsInput: { myArg: addr } }); const result = await visitor.visitArgumentValue(argumentValueNode('myArg')); expect(result).toBe(addr); }); test('should throw when argument is missing', async () => { const visitor = makeVisitor({ argumentsInput: {} }); await expect(visitor.visitArgumentValue(argumentValueNode('myArg'))).rejects.toThrow( /Missing argument \[myArg\] in \[testInstruction\]/, ); }); test('should throw when argument is null', async () => { const visitor = makeVisitor({ argumentsInput: { myArg: null } }); await expect(visitor.visitArgumentValue(argumentValueNode('myArg'))).rejects.toThrow( /Missing argument \[myArg\] in \[testInstruction\]/, ); }); test('should throw when argument cannot be converted to Address', async () => { const visitors: ReturnType[] = [ makeVisitor({ argumentsInput: { myArg: 'not-a-valid-base58' } }), makeVisitor({ argumentsInput: { myArg: { a: 42 } } }), ]; for (const visitor of visitors) { await expect(visitor.visitArgumentValue(argumentValueNode('myArg'))).rejects.toThrow( /Expected \[Address \| PublicKey\] for account \[testAccount\]/, ); } }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/account-default-value/conditionalValueNode.test.ts ================================================ import { argumentValueNode, conditionalValueNode, instructionAccountNode, numberValueNode, publicKeyValueNode, resolverValueNode, } from 'codama'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../../../svm-test-context'; import { ixAccountNodeStub, makeVisitor } from './account-default-value-test-utils'; describe('account-default-value: visitConditionalValue', async () => { const ifTrueAddress = await SvmTestContext.generateAddress(); const ifFalseAddress = await SvmTestContext.generateAddress(); test('should resolve ifTrue branch when argument condition is truthy', async () => { const node = conditionalValueNode({ condition: argumentValueNode('flag'), ifTrue: publicKeyValueNode(ifTrueAddress), }); const visitor = makeVisitor({ argumentsInput: { flag: true } }); const result = await visitor.visitConditionalValue(node); expect(result).toBe(ifTrueAddress); }); test('should resolve ifFalse branch when argument condition is falsy', async () => { const node = conditionalValueNode({ condition: argumentValueNode('flag'), ifFalse: publicKeyValueNode(ifFalseAddress), ifTrue: publicKeyValueNode(ifTrueAddress), }); const visitor = makeVisitor({ argumentsInput: { flag: false } }); const result = await visitor.visitConditionalValue(node); expect(result).toBe(ifFalseAddress); }); test('should return null for optional account when no ifFalse and condition is falsy', async () => { const optionalAccountNode = instructionAccountNode({ isOptional: true, isSigner: false, isWritable: false, name: 'optionalAccount', }); const node = conditionalValueNode({ condition: argumentValueNode('flag'), ifTrue: publicKeyValueNode(ifTrueAddress), }); const visitor = makeVisitor({ argumentsInput: { flag: false }, ixAccountNode: optionalAccountNode, }); const result = await visitor.visitConditionalValue(node); expect(result).toBeNull(); }); test('should throw for required account when no ifFalse and condition is falsy', async () => { const node = conditionalValueNode({ condition: argumentValueNode('flag'), ifTrue: publicKeyValueNode(ifTrueAddress), }); const visitor = makeVisitor({ argumentsInput: { flag: false }, ixAccountNode: { ...ixAccountNodeStub, isOptional: false, }, }); await expect(visitor.visitConditionalValue(node)).rejects.toThrow(/Missing account \[/); }); test('should resolve ifTrue when primitive value matches', async () => { const node = conditionalValueNode({ condition: argumentValueNode('tokenStandard'), ifFalse: publicKeyValueNode(ifFalseAddress), ifTrue: publicKeyValueNode(ifTrueAddress), value: numberValueNode(0), }); const visitor = makeVisitor({ argumentsInput: { tokenStandard: 0 } }); const result = await visitor.visitConditionalValue(node); expect(result).toBe(ifTrueAddress); }); test('should resolve ifFalse when value does not match', async () => { const node = conditionalValueNode({ condition: argumentValueNode('tokenStandard'), ifFalse: publicKeyValueNode(ifFalseAddress), ifTrue: publicKeyValueNode(ifTrueAddress), value: numberValueNode(0), }); const visitor = makeVisitor({ argumentsInput: { tokenStandard: 1 } }); const result = await visitor.visitConditionalValue(node); expect(result).toBe(ifFalseAddress); }); test('should resolve with resolver condition', async () => { const nodeWithTrue = conditionalValueNode({ condition: resolverValueNode('myResolver'), ifFalse: publicKeyValueNode(ifFalseAddress), ifTrue: publicKeyValueNode(ifTrueAddress), }); const visitorWithTrue = makeVisitor({ resolversInput: { myResolver: () => Promise.resolve(true) } }); const result = await visitorWithTrue.visitConditionalValue(nodeWithTrue); expect(result).toBe(ifTrueAddress); const visitorWithFalse = makeVisitor({ resolversInput: { myResolver: () => Promise.resolve(false) } }); const resultFalse = await visitorWithFalse.visitConditionalValue(nodeWithTrue); expect(resultFalse).toBe(ifFalseAddress); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/account-default-value/identityValueNode.test.ts ================================================ import { identityValueNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../../../svm-test-context'; import { makeVisitor } from './account-default-value-test-utils'; describe('account-default-value: visitIdentityValue', () => { test('should return provided address', async () => { const addr = await SvmTestContext.generateAddress(); const visitor = makeVisitor({ accountAddressInput: addr }); const result = await visitor.visitIdentityValue(identityValueNode()); expect(result).toBe(addr); }); test('should throw when address not provided (undefined)', async () => { const visitor = makeVisitor({ accountAddressInput: undefined }); await expect(visitor.visitIdentityValue(identityValueNode())).rejects.toThrow( /Missing account \[testAccount\]/, ); }); test('should throw when address not provided (null)', async () => { const visitor = makeVisitor({ accountAddressInput: null }); await expect(visitor.visitIdentityValue(identityValueNode())).rejects.toThrow( /Missing account \[testAccount\]/, ); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/account-default-value/payerValueNode.test.ts ================================================ import { payerValueNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../../../svm-test-context'; import { makeVisitor } from './account-default-value-test-utils'; describe('account-default-value: visitPayerValue', () => { test('should return provided address', async () => { const addr = await SvmTestContext.generateAddress(); const visitor = makeVisitor({ accountAddressInput: addr }); const result = await visitor.visitPayerValue(payerValueNode()); expect(result).toBe(addr); }); test('should throw when address not provided (undefined)', async () => { const visitor = makeVisitor({ accountAddressInput: undefined }); await expect(visitor.visitPayerValue(payerValueNode())).rejects.toThrow(/Missing account \[testAccount\]/); }); test('should throw when address not provided (null)', async () => { const visitor = makeVisitor({ accountAddressInput: null }); await expect(visitor.visitPayerValue(payerValueNode())).rejects.toThrow(/Missing account \[testAccount\]/); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/account-default-value/pdaValueNode.test.ts ================================================ import { getAddressEncoder, getProgramDerivedAddress } from '@solana/addresses'; import { getUtf8Codec } from '@solana/codecs'; import { argumentValueNode, bytesTypeNode, constantPdaSeedNode, instructionArgumentNode, pdaLinkNode, pdaNode, pdaSeedValueNode, pdaValueNode, programNode, publicKeyTypeNode, rootNode, stringTypeNode, stringValueNode, variablePdaSeedNode, } from 'codama'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../../../svm-test-context'; import { ixNodeStub, makeVisitor } from './account-default-value-test-utils'; describe('account-default-value: visitPdaValue', async () => { const testProgramAddress = await SvmTestContext.generateAddress(); test('should derive PDA with constant seed', async () => { const pda = pdaNode({ name: 'testPda', seeds: [constantPdaSeedNode(stringTypeNode('utf8'), stringValueNode('prefix'))], }); const root = rootNode(programNode({ name: 'test', pdas: [pda], publicKey: testProgramAddress })); const node = pdaValueNode(pdaLinkNode('testPda')); const expectedPda = await getProgramDerivedAddress({ programAddress: testProgramAddress, seeds: [getUtf8Codec().encode('prefix')], }); const visitor = makeVisitor({ root }); const result = await visitor.visitPdaValue(node); expect(result).toBe(expectedPda[0]); }); test('should derive PDA with variable seed from argument', async () => { const ownerAddress = await SvmTestContext.generateAddress(); const pda = pdaNode({ name: 'testPda', seeds: [variablePdaSeedNode('owner', publicKeyTypeNode())], }); const root = rootNode(programNode({ name: 'test', pdas: [pda], publicKey: testProgramAddress })); const node = pdaValueNode(pdaLinkNode('testPda'), [pdaSeedValueNode('owner', argumentValueNode('ownerArg'))]); const ixNode = { ...ixNodeStub, arguments: [instructionArgumentNode({ name: 'ownerArg', type: publicKeyTypeNode() })], }; const expectedPda = await getProgramDerivedAddress({ programAddress: testProgramAddress, seeds: [getAddressEncoder().encode(ownerAddress)], }); const visitor = makeVisitor({ argumentsInput: { ownerArg: ownerAddress }, ixNode, root, }); const result = await visitor.visitPdaValue(node); expect(result).toBe(expectedPda[0]); }); test('should throw when variable seed value node is missing', async () => { const pda = pdaNode({ name: 'testPda', seeds: [variablePdaSeedNode('owner', bytesTypeNode())], }); const root = rootNode(programNode({ name: 'test', pdas: [pda], publicKey: testProgramAddress })); const node = pdaValueNode(pdaLinkNode('testPda')); const visitor = makeVisitor({ root }); await expect(visitor.visitPdaValue(node)).rejects.toThrow( /Referenced node \[owner\] not found in \[testInstruction\]/, ); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/account-default-value/programIdValueNode.test.ts ================================================ import { programIdValueNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { makeVisitor, programAddress } from './account-default-value-test-utils'; describe('account-default-value: visitProgramIdValue', () => { test('should return program public key from root', async () => { const visitor = makeVisitor(); const result = await visitor.visitProgramIdValue(programIdValueNode()); expect(result).toBe(programAddress); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/account-default-value/publicKeyValueNode.test.ts ================================================ import { publicKeyValueNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../../../svm-test-context'; import { makeVisitor } from './account-default-value-test-utils'; describe('account-default-value: visitPublicKeyValue', () => { test('should return public key address', async () => { const addr = await SvmTestContext.generateAddress(); const visitor = makeVisitor(); const result = await visitor.visitPublicKeyValue(publicKeyValueNode(addr)); expect(result).toBe(addr); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/account-default-value/resolverValueNode.test.ts ================================================ import { resolverValueNode } from 'codama'; import { describe, expect, test, vi } from 'vitest'; import { SvmTestContext } from '../../../svm-test-context'; import { makeVisitor } from './account-default-value-test-utils'; describe('account-default-value: visitResolverValue', () => { test('should call resolver and return address', async () => { const addr = await SvmTestContext.generateAddress(); const visitor = makeVisitor({ resolversInput: { myResolver: () => Promise.resolve(addr) }, }); const result = await visitor.visitResolverValue(resolverValueNode('myResolver')); expect(result).toBe(addr); }); test('should throw when resolver is not provided', async () => { const visitor = makeVisitor(); await expect(visitor.visitResolverValue(resolverValueNode('myResolver'))).rejects.toThrow( /Resolver \[myResolver\] not provided for account \[testAccount\]/, ); }); test('should throw when resolver returns null', async () => { const visitor = makeVisitor({ resolversInput: { myResolver: () => Promise.resolve(null) }, }); await expect(visitor.visitResolverValue(resolverValueNode('myResolver'))).rejects.toThrow( /Invalid account address \[testAccount\]: \[null\]/, ); }); test('should throw when resolver returns undefined', async () => { const visitor = makeVisitor({ resolversInput: { myResolver: () => Promise.resolve(undefined) }, }); await expect(visitor.visitResolverValue(resolverValueNode('myResolver'))).rejects.toThrow( /Invalid account address \[testAccount\]: \[undefined\]/, ); }); test('should pass arguments and accounts to resolver', async () => { const addr = await SvmTestContext.generateAddress(); const resolverSpy = vi.fn().mockResolvedValue(addr); const argumentsInput = { amount: 100 }; const accountsInput = { treasury: addr }; const visitor = makeVisitor({ accountsInput, argumentsInput, resolversInput: { myResolver: resolverSpy }, }); await visitor.visitResolverValue(resolverValueNode('myResolver')); expect(resolverSpy).toHaveBeenCalledWith(argumentsInput, accountsInput); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/condition-node-value/accountValueNode.test.ts ================================================ import { accountValueNode, instructionAccountNode, instructionNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../../../svm-test-context'; import { makeVisitor } from './condition-node-value-test-utils'; describe('condition-node-value: visitAccountValue', () => { const ixNodeWithAccount = instructionNode({ accounts: [ instructionAccountNode({ isOptional: true, isSigner: false, isWritable: false, name: 'myAccount', }), ], name: 'testInstruction', }); test('should return null when user provides null', async () => { const visitor = makeVisitor({ accountsInput: { myAccount: null }, ixNode: ixNodeWithAccount, }); const result = await visitor.visitAccountValue(accountValueNode('myAccount')); expect(result).toBeNull(); }); test('should return address when user provides address', async () => { const accAddress = await SvmTestContext.generateAddress(); const visitor = makeVisitor({ accountsInput: { myAccount: accAddress }, ixNode: ixNodeWithAccount, }); const result = await visitor.visitAccountValue(accountValueNode('myAccount')); expect(result).toBe(accAddress); }); test('should throw for unknown account reference', async () => { const visitor = makeVisitor(); await expect(visitor.visitAccountValue(accountValueNode('unknown'))).rejects.toThrow( /Referenced node \[unknown\] not found in \[testInstruction\]/, ); }); test('should throw on circular dependency', async () => { const visitor = makeVisitor({ ixNode: ixNodeWithAccount, resolutionPath: ['myAccount'], }); await expect(visitor.visitAccountValue(accountValueNode('myAccount'))).rejects.toThrow( /Circular dependency detected: \[/, ); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/condition-node-value/argumentValueNode.test.ts ================================================ import { argumentValueNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { makeVisitor } from './condition-node-value-test-utils'; describe('condition-node-value: visitArgumentValue', () => { test('should return argument value', async () => { const visitor = makeVisitor({ argumentsInput: { amount: 42 } }); const result = await visitor.visitArgumentValue(argumentValueNode('amount')); expect(result).toBe(42); }); test('should return undefined for missing argument', async () => { const visitor = makeVisitor({ argumentsInput: {} }); const result = await visitor.visitArgumentValue(argumentValueNode('amount')); expect(result).toBeUndefined(); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/condition-node-value/condition-node-value-test-utils.ts ================================================ import { instructionNode, programNode, rootNode } from 'codama'; import { createConditionNodeValueVisitor } from '../../../../src/instruction-encoding/visitors/condition-node-value'; const rootNodeMock = rootNode(programNode({ name: 'test', publicKey: '11111111111111111111111111111111' })); const ixNodeStub = instructionNode({ name: 'testInstruction' }); export function makeVisitor(overrides?: Partial[0]>) { return createConditionNodeValueVisitor({ accountsInput: undefined, argumentsInput: undefined, ixNode: ixNodeStub, resolutionPath: [], resolversInput: undefined, root: rootNodeMock, ...overrides, }); } ================================================ FILE: packages/dynamic-client/test/unit/visitors/condition-node-value/resolverValueNode.test.ts ================================================ import { resolverValueNode } from 'codama'; import { describe, expect, test, vi } from 'vitest'; import { makeVisitor } from './condition-node-value-test-utils'; describe('condition-node-value: visitResolverValue', () => { test('should return undefined when resolversInput is undefined', async () => { const visitor = makeVisitor(); const result = await visitor.visitResolverValue(resolverValueNode('myResolver')); expect(result).toBeUndefined(); }); test('should return undefined when resolver not in the resolversInput', async () => { const visitor = makeVisitor({ resolversInput: {} }); const result = await visitor.visitResolverValue(resolverValueNode('myResolver')); expect(result).toBeUndefined(); }); test('should call resolver and return result', async () => { const visitor = makeVisitor({ resolversInput: { myResolver: async () => await Promise.resolve(999) }, }); const result = await visitor.visitResolverValue(resolverValueNode('myResolver')); expect(result).toBe(999); }); test('should throw ResolverError when resolver throws', async () => { const visitor = makeVisitor({ resolversInput: { myResolver: () => { throw new Error('some error'); }, }, }); await expect(visitor.visitResolverValue(resolverValueNode('myResolver'))).rejects.toThrow( /Resolver \[myResolver\] threw an error while resolving \[conditionalValueNode\] \[myResolver\]/, ); }); test('should pass arguments and accounts to resolver', async () => { const resolverSpy = vi.fn().mockReturnValue('resolved'); const argumentsInput = { amount: 100 }; const accountsInput = { treasury: null }; const visitor = makeVisitor({ accountsInput, argumentsInput, resolversInput: { myResolver: resolverSpy }, }); const result = await visitor.visitResolverValue(resolverValueNode('myResolver')); expect(result).toBe('resolved'); expect(resolverSpy).toHaveBeenCalledWith(argumentsInput, accountsInput); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/default-value-encoder/booleanValueNode.test.ts ================================================ import { getBooleanCodec } from '@solana/codecs'; import { booleanTypeNode, booleanValueNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { makeVisitor } from './default-value-encoder-test-utils'; describe('default-value-encoder: visitBooleanValue', () => { test('should encode true', () => { const visitor = makeVisitor(booleanTypeNode()); const result = visitor.visitBooleanValue(booleanValueNode(true)); expect(result).toEqual(getBooleanCodec().encode(true)); }); test('should encode false', () => { const visitor = makeVisitor(booleanTypeNode()); const result = visitor.visitBooleanValue(booleanValueNode(false)); expect(result).toEqual(getBooleanCodec().encode(false)); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/default-value-encoder/bytesValueNode.test.ts ================================================ import { getBase16Codec, getBase58Codec, getUtf8Codec } from '@solana/codecs'; import { bytesTypeNode, bytesValueNode, fixedSizeTypeNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../../../svm-test-context'; import { makeVisitor } from './default-value-encoder-test-utils'; describe('default-value-encoder: visitBytesValue', () => { test('should encode base16 bytes', () => { const visitor = makeVisitor(fixedSizeTypeNode(bytesTypeNode(), 4)); const result = visitor.visitBytesValue(bytesValueNode('base16', 'deadbeef')); expect(result).toEqual(getBase16Codec().encode('deadbeef')); }); test('should encode base58 bytes', async () => { const bs58 = await SvmTestContext.generateAddress(); const visitor = makeVisitor(fixedSizeTypeNode(bytesTypeNode(), 32)); const result = visitor.visitBytesValue(bytesValueNode('base58', bs58)); expect(result).toEqual(getBase58Codec().encode(bs58)); }); test('should encode utf8 bytes', () => { const visitor = makeVisitor(fixedSizeTypeNode(bytesTypeNode(), 5)); const result = visitor.visitBytesValue(bytesValueNode('utf8', 'hello')); expect(result).toEqual(getUtf8Codec().encode('hello')); }); test('should encode empty bytes', () => { const visitor = makeVisitor(fixedSizeTypeNode(bytesTypeNode(), 0)); const result = visitor.visitBytesValue(bytesValueNode('base16', '')); expect(result).toEqual(new Uint8Array(0)); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/default-value-encoder/default-value-encoder-test-utils.ts ================================================ import { getNodeCodec } from '@codama/dynamic-codecs'; import type { InstructionArgumentNode, TypeNode } from 'codama'; import { instructionArgumentNode, instructionNode, programNode, rootNode } from 'codama'; import { createDefaultValueEncoderVisitor } from '../../../../src/instruction-encoding/visitors/default-value-encoder'; const root = rootNode(programNode({ name: 'test_program', publicKey: '11111111111111111111111111111111' })); export function makeVisitor(argType: TypeNode) { const ixArgNode: InstructionArgumentNode = instructionArgumentNode({ name: 'testArg', type: argType, }); const ixNode = instructionNode({ arguments: [ixArgNode], name: 'testInstruction', }); const codec = getNodeCodec([root, root.program, ixNode, ixArgNode]); return createDefaultValueEncoderVisitor(codec); } ================================================ FILE: packages/dynamic-client/test/unit/visitors/default-value-encoder/enumValueNode.test.ts ================================================ import { enumEmptyVariantTypeNode, enumTypeNode, enumValueNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { makeVisitor } from './default-value-encoder-test-utils'; describe('default-value-encoder: visitEnumValue', () => { test('should encode variants', () => { const visitor = makeVisitor( enumTypeNode([enumEmptyVariantTypeNode('variantA'), enumEmptyVariantTypeNode('variantB')]), ); const variantA = visitor.visitEnumValue(enumValueNode('testEnum', 'variantA')); expect(variantA).toEqual(new Uint8Array([0])); const variantB = visitor.visitEnumValue(enumValueNode('testEnum', 'variantB')); expect(variantB).toEqual(new Uint8Array([1])); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/default-value-encoder/noneValueNode.test.ts ================================================ import { noneValueNode, numberTypeNode, optionTypeNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { makeVisitor } from './default-value-encoder-test-utils'; describe('default-value-encoder: visitNoneValue', () => { test('should encode none as option prefix byte 0', () => { const visitor = makeVisitor(optionTypeNode(numberTypeNode('u8'))); const result = visitor.visitNoneValue(noneValueNode()); expect(result).toEqual(new Uint8Array([0])); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/default-value-encoder/numberValueNode.test.ts ================================================ import { getU8Codec, getU32Codec } from '@solana/codecs'; import { numberTypeNode, numberValueNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { makeVisitor } from './default-value-encoder-test-utils'; describe('default-value-encoder: visitNumberValue', () => { test('should encode u8 value', () => { const visitor = makeVisitor(numberTypeNode('u8')); const result = visitor.visitNumberValue(numberValueNode(42)); expect(result).toEqual(getU8Codec().encode(42)); }); test('should encode zero', () => { const visitor = makeVisitor(numberTypeNode('u8')); const result = visitor.visitNumberValue(numberValueNode(0)); expect(result).toEqual(getU8Codec().encode(0)); }); test('should encode u32 value', () => { const visitor = makeVisitor(numberTypeNode('u32')); const result = visitor.visitNumberValue(numberValueNode(100_000)); expect(result).toEqual(getU32Codec().encode(100_000)); }); test('should encode max u8 value', () => { const visitor = makeVisitor(numberTypeNode('u8')); const result = visitor.visitNumberValue(numberValueNode(255)); expect(result).toEqual(getU8Codec().encode(255)); }); test('should throw on overflow for u8 value', () => { const visitor = makeVisitor(numberTypeNode('u8')); expect(() => visitor.visitNumberValue(numberValueNode(1000))).toThrow(); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/default-value-encoder/publicKeyValueNode.test.ts ================================================ import { getAddressCodec } from '@solana/addresses'; import { publicKeyTypeNode, publicKeyValueNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../../../svm-test-context'; import { makeVisitor } from './default-value-encoder-test-utils'; describe('default-value-encoder: visitPublicKeyValue', () => { test('should encode public key as 32 bytes', async () => { const pubkey = await SvmTestContext.generateAddress(); const visitor = makeVisitor(publicKeyTypeNode()); const result = visitor.visitPublicKeyValue(publicKeyValueNode(pubkey)); expect(result).toEqual(getAddressCodec().encode(pubkey)); expect(result.length).toBe(32); }); test('should throw for invalid public key', () => { const invalidPubkey = 'not-a-valid-pubkey'; const visitor = makeVisitor(publicKeyTypeNode()); expect(() => visitor.visitPublicKeyValue(publicKeyValueNode(invalidPubkey))).toThrow(); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/default-value-encoder/stringValueNode.test.ts ================================================ import { getBase16Codec, getBase58Codec, getUtf8Codec } from '@solana/codecs'; import { fixedSizeTypeNode, stringTypeNode, stringValueNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { makeVisitor } from './default-value-encoder-test-utils'; describe('default-value-encoder: visitStringValue', () => { test('should encode utf8 string', () => { const visitor = makeVisitor(fixedSizeTypeNode(stringTypeNode('utf8'), 5)); const result = visitor.visitStringValue(stringValueNode('hello')); expect(result).toEqual(getUtf8Codec().encode('hello')); }); test('should encode base16 string', () => { const visitor = makeVisitor(fixedSizeTypeNode(stringTypeNode('base16'), 4)); const result = visitor.visitStringValue(stringValueNode('deadbeef')); expect(result).toEqual(getBase16Codec().encode('deadbeef')); }); test('should encode base58 string', () => { const visitor = makeVisitor(fixedSizeTypeNode(stringTypeNode('base58'), 3)); const result = visitor.visitStringValue(stringValueNode('abc')); expect(result).toEqual(getBase58Codec().encode('abc')); }); test('should encode empty string', () => { const visitor = makeVisitor(fixedSizeTypeNode(stringTypeNode('utf8'), 0)); const result = visitor.visitStringValue(stringValueNode('')); expect(result).toEqual(getUtf8Codec().encode('')); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/input-value-transformer/amountTypeNode.test.ts ================================================ import { amountTypeNode, numberTypeNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { createInputValueTransformer } from '../../../../src/instruction-encoding/visitors/input-value-transformer'; import { rootNodeMock } from './input-value-transformer-test-utils'; describe('amountTypeNode', () => { test('should delegate to inner number type (pass-through)', () => { const transformer = createInputValueTransformer(amountTypeNode(numberTypeNode('u64'), 2, 'USD'), rootNodeMock); expect(transformer(100)).toBe(100); expect(transformer(0)).toBe(0); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/input-value-transformer/arrayTypeNode.test.ts ================================================ import { arrayTypeNode, bytesTypeNode, numberTypeNode, prefixedCountNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { createInputValueTransformer } from '../../../../src/instruction-encoding/visitors/input-value-transformer'; import { rootNodeMock } from './input-value-transformer-test-utils'; describe('arrayTypeNode', () => { test('should transform array items with bytes inner type', () => { const transformer = createInputValueTransformer( arrayTypeNode(bytesTypeNode(), prefixedCountNode(numberTypeNode('u32'))), rootNodeMock, { bytesEncoding: 'base16' }, ); const input = [new Uint8Array([0x01]), new Uint8Array([0x02])]; expect(transformer(input)).toEqual([ ['base16', '01'], ['base16', '02'], ]); }); test('should pass through array of primitives', () => { const transformer = createInputValueTransformer( arrayTypeNode(numberTypeNode('u8'), prefixedCountNode(numberTypeNode('u32'))), rootNodeMock, ); expect(transformer([1, 2, 3])).toEqual([1, 2, 3]); }); test('should throw for non-array input', () => { const transformer = createInputValueTransformer( arrayTypeNode(numberTypeNode('u8'), prefixedCountNode(numberTypeNode('u32'))), rootNodeMock, ); expect(() => transformer('not an array')).toThrow(/Expected \[array\] for \[arrayTypeNode\]/); expect(() => transformer(42)).toThrow(/Expected \[array\] for \[arrayTypeNode\]/); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/input-value-transformer/booleanTypeNode.test.ts ================================================ import { booleanTypeNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { createInputValueTransformer } from '../../../../src/instruction-encoding/visitors/input-value-transformer'; import { rootNodeMock } from './input-value-transformer-test-utils'; describe('booleanTypeNode', () => { test('should pass through boolean values', () => { const transformer = createInputValueTransformer(booleanTypeNode(), rootNodeMock); expect(transformer(true)).toBe(true); expect(transformer(false)).toBe(false); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/input-value-transformer/bytesTypeNode.test.ts ================================================ import { bytesTypeNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { createInputValueTransformer } from '../../../../src/instruction-encoding/visitors/input-value-transformer'; import { rootNodeMock } from './input-value-transformer-test-utils'; describe('bytesTypeNode', () => { test('should transform Uint8Array or number[] to tuple for bytesTypeNode', () => { const transformer = createInputValueTransformer(bytesTypeNode(), rootNodeMock, { bytesEncoding: 'base16' }); // 'Hello' as bytes: [72, 101, 108, 108, 111] -> base16: '48656c6c6f' const inputNumbers = [72, 101, 108, 108, 111]; const inputUint8 = new Uint8Array(inputNumbers); const resultWithUint8 = transformer(inputUint8); const resultWithNumbers = transformer(inputNumbers); const expectedResult = ['base16', '48656c6c6f']; expect(resultWithUint8).toEqual(expectedResult); expect(resultWithNumbers).toEqual(expectedResult); }); test('should throw error for non-Uint8Array input', () => { const transformer = createInputValueTransformer(bytesTypeNode(), rootNodeMock, { bytesEncoding: 'base16' }); const expectedMessage = /Expected \[Uint8Array \| number\[\]\] for \[bytesTypeNode\]/; expect(() => transformer(null)).toThrow(expectedMessage); expect(() => transformer(undefined)).toThrow(expectedMessage); expect(() => transformer('not a Uint8Array')).toThrow(expectedMessage); expect(() => transformer(123)).toThrow(expectedMessage); expect(() => transformer({ data: [1, 2, 3] })).toThrow(expectedMessage); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/input-value-transformer/dateTimeTypeNode.test.ts ================================================ import { dateTimeTypeNode, numberTypeNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { createInputValueTransformer } from '../../../../src/instruction-encoding/visitors/input-value-transformer'; import { rootNodeMock } from './input-value-transformer-test-utils'; describe('dateTimeTypeNode', () => { test('should delegate to inner number type (pass-through)', () => { const transformer = createInputValueTransformer(dateTimeTypeNode(numberTypeNode('i64')), rootNodeMock); expect(transformer(1700000000)).toBe(1700000000); expect(transformer(0)).toBe(0); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/input-value-transformer/definedTypeLinkNode.test.ts ================================================ import { definedTypeLinkNode, definedTypeNode, numberTypeNode, programNode, rootNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { createInputValueTransformer } from '../../../../src/instruction-encoding/visitors/input-value-transformer'; describe('definedTypeLinkNode', () => { test('should resolve defined type and delegate', () => { const root = rootNode( programNode({ definedTypes: [definedTypeNode({ name: 'myNumber', type: numberTypeNode('u64') })], name: 'test', publicKey: '11111111111111111111111111111111', }), ); const transformer = createInputValueTransformer(definedTypeLinkNode('myNumber'), root); expect(transformer(42)).toBe(42); }); test('should throw for unknown type name', () => { const root = rootNode( programNode({ name: 'test', publicKey: '11111111111111111111111111111111', }), ); expect(() => createInputValueTransformer(definedTypeLinkNode('nonExistent'), root)).toThrow( /Could not find linked node \[nonExistent\] from \[definedTypeLinkNode\]/, ); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/input-value-transformer/enumTypeNode.test.ts ================================================ import { arrayTypeNode, bytesTypeNode, definedTypeLinkNode, definedTypeNode, enumEmptyVariantTypeNode, enumStructVariantTypeNode, enumTupleVariantTypeNode, enumTypeNode, numberTypeNode, optionTypeNode, prefixedCountNode, programNode, rootNode, structFieldTypeNode, structTypeNode, tupleTypeNode, } from 'codama'; import { describe, expect, test } from 'vitest'; import { createInputValueTransformer } from '../../../../src/instruction-encoding/visitors/input-value-transformer'; import { rootNodeMock } from './input-value-transformer-test-utils'; describe('enumTypeNode', () => { // Based on pmp-idl.json, mpl-token-metadata-idl.json, token-2022-idl.json test('should pass through scalar enum (number)', () => { // Based on pmp-idl.json: accountDiscriminator enum const scalarEnum = enumTypeNode([ enumEmptyVariantTypeNode('empty'), enumEmptyVariantTypeNode('buffer'), enumEmptyVariantTypeNode('metadata'), ]); const transformer = createInputValueTransformer(scalarEnum, rootNodeMock); expect(transformer(0)).toBe(0); expect(transformer(1)).toBe(1); expect(transformer(2)).toBe(2); }); test('should pass through scalar enum (string)', () => { const scalarEnum = enumTypeNode([enumEmptyVariantTypeNode('initialized'), enumEmptyVariantTypeNode('frozen')]); const transformer = createInputValueTransformer(scalarEnum, rootNodeMock); expect(transformer('initialized')).toBe('initialized'); expect(transformer('frozen')).toBe('frozen'); }); test('should pass through empty variant enum', () => { const dataEnum = enumTypeNode([ enumEmptyVariantTypeNode('none'), enumEmptyVariantTypeNode('utf8'), enumEmptyVariantTypeNode('base58'), ]); const transformer = createInputValueTransformer(dataEnum, rootNodeMock); const input = { __kind: 'none' }; expect(transformer(input)).toEqual({ __kind: 'None' }); }); test('should transform bytes in struct variant', () => { // Based on mpl-token-metadata-idl.json: complex enum with struct variants const enumWithStructVariant = enumTypeNode([ enumEmptyVariantTypeNode('empty'), enumStructVariantTypeNode( 'withData', structTypeNode([ structFieldTypeNode({ name: 'id', type: numberTypeNode('u32') }), structFieldTypeNode({ name: 'data', type: bytesTypeNode() }), ]), ), ]); const transformer = createInputValueTransformer(enumWithStructVariant, rootNodeMock, { bytesEncoding: 'base16', }); const input = { __kind: 'withData', data: new Uint8Array([1, 2, 3]), id: 42, }; expect(transformer(input)).toEqual({ __kind: 'WithData', data: ['base16', '010203'], id: 42, }); }); test('should transform bytes in tuple variant', () => { const enumWithTupleVariant = enumTypeNode([ enumEmptyVariantTypeNode('empty'), enumTupleVariantTypeNode('withBytes', tupleTypeNode([bytesTypeNode(), numberTypeNode('u8')])), ]); const transformer = createInputValueTransformer(enumWithTupleVariant, rootNodeMock, { bytesEncoding: 'base16', }); const input = { __kind: 'withBytes', fields: [new Uint8Array([0xde, 0xad]), 255], }; expect(transformer(input)).toEqual({ __kind: 'WithBytes', fields: [['base16', 'dead'], 255], }); }); test('should throw on unknown variant', () => { const enumWithVariants = enumTypeNode([enumEmptyVariantTypeNode('known1'), enumEmptyVariantTypeNode('known2')]); const transformer = createInputValueTransformer(enumWithVariants, rootNodeMock); const input = { __kind: 'unknownVariant', someData: 123 }; expect(() => transformer(input)).toThrow(/Expected \[one of \[known1, known2\]\] for \[enumTypeNode\]/); }); test('should pass through non-object input for enumTypeNode', () => { const enumNode = enumTypeNode([enumEmptyVariantTypeNode('variant1'), enumEmptyVariantTypeNode('variant2')]); const transformer = createInputValueTransformer(enumNode, rootNodeMock); expect(transformer(null)).toBe(null); expect(transformer(undefined)).toBe(undefined); expect(transformer('string')).toBe('string'); }); test('should handle enum without __kind discriminator', () => { const enumNode = enumTypeNode([enumEmptyVariantTypeNode('variant1')]); const transformer = createInputValueTransformer(enumNode, rootNodeMock); // Object without __kind should pass through const input = { someField: 'value' }; expect(transformer(input)).toEqual(input); }); test('should handle nested enum with multiple bytes fields in struct variant', () => { // Complex real-world scenario const complexEnum = enumTypeNode([ enumEmptyVariantTypeNode('none'), enumStructVariantTypeNode( 'complex', structTypeNode([ structFieldTypeNode({ name: 'id', type: numberTypeNode('u32') }), structFieldTypeNode({ name: 'key', type: bytesTypeNode() }), structFieldTypeNode({ name: 'value', type: bytesTypeNode() }), structFieldTypeNode({ name: 'nested', type: optionTypeNode(bytesTypeNode()), }), ]), ), ]); const transformer = createInputValueTransformer(complexEnum, rootNodeMock, { bytesEncoding: 'base16' }); const input = { __kind: 'complex', id: 100, key: new Uint8Array([1, 2]), nested: new Uint8Array([5, 6]), value: new Uint8Array([3, 4]), }; expect(transformer(input)).toEqual({ __kind: 'Complex', id: 100, key: ['base16', '0102'], nested: ['base16', '0506'], value: ['base16', '0304'], }); }); test('should handle enum with array of bytes in struct variant', () => { const enumWithArray = enumTypeNode([ enumStructVariantTypeNode( 'withArray', structTypeNode([ structFieldTypeNode({ name: 'items', type: arrayTypeNode(bytesTypeNode(), prefixedCountNode(numberTypeNode('u32'))), }), ]), ), ]); const transformer = createInputValueTransformer(enumWithArray, rootNodeMock, { bytesEncoding: 'base16' }); const input = { __kind: 'withArray', items: [new Uint8Array([1, 2]), new Uint8Array([3, 4])], }; expect(transformer(input)).toEqual({ __kind: 'WithArray', items: [ ['base16', '0102'], ['base16', '0304'], ], }); }); test('should throw on tuple variant without fields', () => { const enumWithTuple = enumTypeNode([ enumTupleVariantTypeNode('tuple', tupleTypeNode([numberTypeNode('u32'), bytesTypeNode()])), ]); const transformer = createInputValueTransformer(enumWithTuple, rootNodeMock, { bytesEncoding: 'base16' }); const input = { __kind: 'tuple', someOtherProp: 123 }; expect(() => transformer(input)).toThrow(/Expected \[array \(fields\)\] for \[enumTupleVariantTypeNode\]/); }); test('should handle deeply nested enum variants', () => { // Enum containing another enum in struct variant const innerEnum = enumTypeNode([ enumEmptyVariantTypeNode('inner1'), enumStructVariantTypeNode( 'inner2', structTypeNode([structFieldTypeNode({ name: 'data', type: bytesTypeNode() })]), ), ]); const root = rootNode( programNode({ definedTypes: [ definedTypeNode({ name: 'InnerEnum', type: innerEnum, }), ], name: 'test', publicKey: '11111111111111111111111111111111', }), ); const outerEnum = enumTypeNode([ enumStructVariantTypeNode( 'outer', structTypeNode([structFieldTypeNode({ name: 'inner', type: definedTypeLinkNode('InnerEnum') })]), ), ]); const transformer = createInputValueTransformer(outerEnum, root, { bytesEncoding: 'base16' }); const input = { __kind: 'outer', inner: { __kind: 'inner2', data: new Uint8Array([0xff, 0xee]), }, }; expect(transformer(input)).toEqual({ __kind: 'Outer', inner: { __kind: 'Inner2', data: ['base16', 'ffee'], }, }); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/input-value-transformer/fixedSizeTypeNode.test.ts ================================================ import { bytesTypeNode, fixedSizeTypeNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { createInputValueTransformer } from '../../../../src/instruction-encoding/visitors/input-value-transformer'; import { rootNodeMock } from './input-value-transformer-test-utils'; describe('fixedSizeTypeNode', () => { test('should delegate to inner type (bytes transform visible)', () => { const transformer = createInputValueTransformer(fixedSizeTypeNode(bytesTypeNode(), 4), rootNodeMock, { bytesEncoding: 'base16', }); const input = new Uint8Array([0xde, 0xad, 0xbe, 0xef]); expect(transformer(input)).toEqual(['base16', 'deadbeef']); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/input-value-transformer/hiddenPrefixTypeNode.test.ts ================================================ import { bytesTypeNode, bytesValueNode, constantValueNode, fixedSizeTypeNode, hiddenPrefixTypeNode, numberTypeNode, stringTypeNode, stringValueNode, } from 'codama'; import { describe, expect, test } from 'vitest'; import { createInputValueTransformer } from '../../../../src/instruction-encoding/visitors/input-value-transformer'; import { rootNodeMock } from './input-value-transformer-test-utils'; describe('hiddenPrefixTypeNode', () => { test('should delegate to inner type [bytesTypeNode]', () => { const transformer = createInputValueTransformer( hiddenPrefixTypeNode(bytesTypeNode(), [constantValueNode(bytesTypeNode(), bytesValueNode('base16', 'ff'))]), rootNodeMock, { bytesEncoding: 'base16' }, ); const input = new Uint8Array([0x01, 0x02]); expect(transformer(input)).toEqual(['base16', '0102']); }); test('should delegate to inner type [numberTypeNode]', () => { const transformer = createInputValueTransformer( hiddenPrefixTypeNode(numberTypeNode('u32'), [ constantValueNode(bytesTypeNode(), bytesValueNode('base16', 'ffff')), ]), rootNodeMock, { bytesEncoding: 'base16' }, ); expect(transformer(42)).toEqual(42); }); test('should delegate to inner type [stringTypeNode]', () => { const transformer = createInputValueTransformer( hiddenPrefixTypeNode(fixedSizeTypeNode(stringTypeNode('utf8'), 10), [ constantValueNode(stringTypeNode('utf8'), stringValueNode('Hello')), ]), rootNodeMock, ); expect(transformer('World')).toEqual('World'); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/input-value-transformer/hiddenSuffixTypeNode.test.ts ================================================ import { bytesTypeNode, bytesValueNode, constantValueNode, hiddenSuffixTypeNode, numberTypeNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { createInputValueTransformer } from '../../../../src/instruction-encoding/visitors/input-value-transformer'; import { rootNodeMock } from './input-value-transformer-test-utils'; describe('hiddenSuffixTypeNode', () => { test('should delegate to inner type', () => { const transformer = createInputValueTransformer( hiddenSuffixTypeNode(bytesTypeNode(), [constantValueNode(bytesTypeNode(), bytesValueNode('base16', 'ff'))]), rootNodeMock, { bytesEncoding: 'base16' }, ); const input = new Uint8Array([0x01, 0x02]); expect(transformer(input)).toEqual(['base16', '0102']); }); test('should delegate to inner type [numberTypeNode]', () => { const transformer = createInputValueTransformer( hiddenSuffixTypeNode(numberTypeNode('u32'), [ constantValueNode(bytesTypeNode(), bytesValueNode('base16', 'ffff')), ]), rootNodeMock, { bytesEncoding: 'base16' }, ); expect(transformer(42)).toEqual(42); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/input-value-transformer/input-value-transformer-test-utils.ts ================================================ import { programNode, rootNode } from 'codama'; // Shared root node mock for tests export const rootNodeMock = rootNode( programNode({ name: 'test', publicKey: '11111111111111111111111111111111', }), ); ================================================ FILE: packages/dynamic-client/test/unit/visitors/input-value-transformer/mapTypeNode.test.ts ================================================ import { bytesTypeNode, mapTypeNode, numberTypeNode, prefixedCountNode, stringTypeNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { createInputValueTransformer } from '../../../../src/instruction-encoding/visitors/input-value-transformer'; import { rootNodeMock } from './input-value-transformer-test-utils'; describe('mapTypeNode', () => { test('should transform map values with bytes inner type', () => { const transformer = createInputValueTransformer( mapTypeNode(stringTypeNode('utf8'), bytesTypeNode(), prefixedCountNode(numberTypeNode('u32'))), rootNodeMock, { bytesEncoding: 'base16' }, ); const input = { key1: new Uint8Array([0x01]), key2: new Uint8Array([0x02]) }; expect(transformer(input)).toEqual({ key1: ['base16', '01'], key2: ['base16', '02'] }); }); test('should pass through map with primitive values', () => { const transformer = createInputValueTransformer( mapTypeNode(stringTypeNode('utf8'), numberTypeNode('u64'), prefixedCountNode(numberTypeNode('u32'))), rootNodeMock, ); expect(transformer({ a: 1, b: 2 })).toEqual({ a: 1, b: 2 }); }); test('should throw for non-object input', () => { const transformer = createInputValueTransformer( mapTypeNode(stringTypeNode('utf8'), numberTypeNode('u8'), prefixedCountNode(numberTypeNode('u32'))), rootNodeMock, ); expect(() => transformer('not an object')).toThrow(/Expected \[object\] for \[mapTypeNode\]/); expect(() => transformer([1, 2])).toThrow(/Expected \[object\] for \[mapTypeNode\]/); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/input-value-transformer/numberTypeNode.test.ts ================================================ import { numberTypeNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { createInputValueTransformer } from '../../../../src/instruction-encoding/visitors/input-value-transformer'; import { rootNodeMock } from './input-value-transformer-test-utils'; describe('numberTypeNode', () => { test('should pass through number values', () => { const transformer = createInputValueTransformer(numberTypeNode('u64'), rootNodeMock); expect(transformer(0)).toBe(0); expect(transformer(42)).toBe(42); expect(transformer(999)).toBe(999); expect(transformer(Number.MAX_SAFE_INTEGER)).toBe(Number.MAX_SAFE_INTEGER); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/input-value-transformer/optionTypeNode.test.ts ================================================ import { bytesTypeNode, numberTypeNode, optionTypeNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { createInputValueTransformer } from '../../../../src/instruction-encoding/visitors/input-value-transformer'; import { rootNodeMock } from './input-value-transformer-test-utils'; describe('optionTypeNode', () => { test('should pass through null and undefined', () => { const transformer = createInputValueTransformer( optionTypeNode(numberTypeNode('u8'), { prefix: numberTypeNode('u8') }), rootNodeMock, ); expect(transformer(null)).toBe(null); expect(transformer(undefined)).toBe(undefined); }); test('should transform non-null inner value', () => { const transformer = createInputValueTransformer( optionTypeNode(bytesTypeNode(), { prefix: numberTypeNode('u8') }), rootNodeMock, { bytesEncoding: 'base16' }, ); expect(transformer(new Uint8Array([0xff]))).toEqual(['base16', 'ff']); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/input-value-transformer/postOffsetTypeNode.test.ts ================================================ import { bytesTypeNode, numberTypeNode, postOffsetTypeNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { createInputValueTransformer } from '../../../../src/instruction-encoding/visitors/input-value-transformer'; import { rootNodeMock } from './input-value-transformer-test-utils'; describe('postOffsetTypeNode', () => { test('should delegate to inner type [bytesTypeNode]', () => { const transformer = createInputValueTransformer(postOffsetTypeNode(bytesTypeNode(), 0), rootNodeMock, { bytesEncoding: 'base16', }); const input = new Uint8Array([0xab, 0xcd]); expect(transformer(input)).toEqual(['base16', 'abcd']); }); test('should delegate to inner type [numberTypeNode]', () => { const transformer = createInputValueTransformer(postOffsetTypeNode(numberTypeNode('u32'), 0), rootNodeMock); expect(transformer(42)).toEqual(42); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/input-value-transformer/preOffsetTypeNode.test.ts ================================================ import { bytesTypeNode, preOffsetTypeNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { createInputValueTransformer } from '../../../../src/instruction-encoding/visitors/input-value-transformer'; import { rootNodeMock } from './input-value-transformer-test-utils'; describe('preOffsetTypeNode', () => { test('should delegate to inner type', () => { const transformer = createInputValueTransformer(preOffsetTypeNode(bytesTypeNode(), 0), rootNodeMock, { bytesEncoding: 'base16', }); const input = new Uint8Array([0xab, 0xcd]); expect(transformer(input)).toEqual(['base16', 'abcd']); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/input-value-transformer/publicKeyTypeNode.test.ts ================================================ import { publicKeyTypeNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { createInputValueTransformer } from '../../../../src/instruction-encoding/visitors/input-value-transformer'; import { SvmTestContext } from '../../../svm-test-context'; import { rootNodeMock } from './input-value-transformer-test-utils'; describe('publicKeyTypeNode', () => { test('should pass through public key string', async () => { const transformer = createInputValueTransformer(publicKeyTypeNode(), rootNodeMock); const pubkey = await SvmTestContext.generateAddress(); expect(transformer(pubkey)).toBe(pubkey); }); test('should pass through any value unchanged', () => { const transformer = createInputValueTransformer(publicKeyTypeNode(), rootNodeMock); expect(transformer(null)).toBe(null); expect(transformer(123)).toBe(123); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/input-value-transformer/remainderOptionTypeNode.test.ts ================================================ import { bytesTypeNode, remainderOptionTypeNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { createInputValueTransformer } from '../../../../src/instruction-encoding/visitors/input-value-transformer'; import { rootNodeMock } from './input-value-transformer-test-utils'; describe('remainderOptionTypeNode', () => { test('should pass through null and undefined', () => { const transformer = createInputValueTransformer(remainderOptionTypeNode(bytesTypeNode()), rootNodeMock); expect(transformer(null)).toBe(null); expect(transformer(undefined)).toBe(undefined); }); test('should transform non-null inner value', () => { const transformer = createInputValueTransformer(remainderOptionTypeNode(bytesTypeNode()), rootNodeMock, { bytesEncoding: 'base16', }); expect(transformer(new Uint8Array([0xab]))).toEqual(['base16', 'ab']); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/input-value-transformer/sentinelTypeNode.test.ts ================================================ import { bytesTypeNode, bytesValueNode, constantValueNode, sentinelTypeNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { createInputValueTransformer } from '../../../../src/instruction-encoding/visitors/input-value-transformer'; import { rootNodeMock } from './input-value-transformer-test-utils'; describe('sentinelTypeNode', () => { test('should delegate to inner type', () => { const transformer = createInputValueTransformer( sentinelTypeNode(bytesTypeNode(), constantValueNode(bytesTypeNode(), bytesValueNode('base16', 'ff'))), rootNodeMock, { bytesEncoding: 'base16' }, ); const input = new Uint8Array([0xab, 0xcd]); expect(transformer(input)).toEqual(['base16', 'abcd']); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/input-value-transformer/setTypeNode.test.ts ================================================ import { bytesTypeNode, numberTypeNode, prefixedCountNode, setTypeNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { createInputValueTransformer } from '../../../../src/instruction-encoding/visitors/input-value-transformer'; import { rootNodeMock } from './input-value-transformer-test-utils'; describe('setTypeNode', () => { test('should transform set items with bytes inner type', () => { const transformer = createInputValueTransformer( setTypeNode(bytesTypeNode(), prefixedCountNode(numberTypeNode('u32'))), rootNodeMock, { bytesEncoding: 'base16' }, ); const input = [new Uint8Array([0xaa]), new Uint8Array([0xbb])]; expect(transformer(input)).toEqual([ ['base16', 'aa'], ['base16', 'bb'], ]); }); test('should throw for non-array input', () => { const transformer = createInputValueTransformer( setTypeNode(numberTypeNode('u8'), prefixedCountNode(numberTypeNode('u32'))), rootNodeMock, ); expect(() => transformer('not an array')).toThrow(/Expected \[array\] for \[setTypeNode\]/); expect(() => transformer({ a: 1 })).toThrow(/Expected \[array\] for \[setTypeNode\]/); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/input-value-transformer/sizePrefixTypeNode.test.ts ================================================ import { bytesTypeNode, numberTypeNode, sizePrefixTypeNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { createInputValueTransformer } from '../../../../src/instruction-encoding/visitors/input-value-transformer'; import { rootNodeMock } from './input-value-transformer-test-utils'; describe('sizePrefixTypeNode', () => { test('should delegate to inner type', () => { const transformer = createInputValueTransformer( sizePrefixTypeNode(bytesTypeNode(), numberTypeNode('u32')), rootNodeMock, { bytesEncoding: 'base16' }, ); const input = new Uint8Array([0x01, 0x02]); expect(transformer(input)).toEqual(['base16', '0102']); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/input-value-transformer/solAmountTypeNode.test.ts ================================================ import { numberTypeNode, solAmountTypeNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { createInputValueTransformer } from '../../../../src/instruction-encoding/visitors/input-value-transformer'; import { rootNodeMock } from './input-value-transformer-test-utils'; describe('solAmountTypeNode', () => { test('should delegate to inner number type (pass-through)', () => { const transformer = createInputValueTransformer(solAmountTypeNode(numberTypeNode('u64')), rootNodeMock); expect(transformer(1000000000)).toBe(1000000000); expect(transformer(0)).toBe(0); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/input-value-transformer/stringTypeNode.test.ts ================================================ import { stringTypeNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { createInputValueTransformer } from '../../../../src/instruction-encoding/visitors/input-value-transformer'; import { rootNodeMock } from './input-value-transformer-test-utils'; describe('stringTypeNode', () => { test('should pass through string values', () => { const transformer = createInputValueTransformer(stringTypeNode('utf8'), rootNodeMock); expect(transformer('hello')).toBe('hello'); expect(transformer('')).toBe(''); expect(transformer('🎉 unicode')).toBe('🎉 unicode'); }); test('should pass through non-string values unchanged', () => { const transformer = createInputValueTransformer(stringTypeNode('utf8'), rootNodeMock); expect(transformer(42)).toBe(42); expect(transformer(null)).toBe(null); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/input-value-transformer/structTypeNode.test.ts ================================================ import { arrayTypeNode, bytesTypeNode, fixedCountNode, numberTypeNode, optionTypeNode, stringTypeNode, structFieldTypeNode, structTypeNode, } from 'codama'; import { describe, expect, test } from 'vitest'; import { createInputValueTransformer } from '../../../../src/instruction-encoding/visitors/input-value-transformer'; import { rootNodeMock } from './input-value-transformer-test-utils'; describe('structTypeNode', () => { test('should transform struct with bytes field', () => { const transformer = createInputValueTransformer( structTypeNode([ structFieldTypeNode({ name: 'name', type: stringTypeNode('utf8') }), structFieldTypeNode({ name: 'data', type: bytesTypeNode() }), ]), rootNodeMock, { bytesEncoding: 'base16' }, ); const input = { data: new Uint8Array([1, 2, 3]), name: 'test', }; expect(transformer(input)).toEqual({ data: ['base16', '010203'], name: 'test', }); }); test('should transform complex nested structure with bytes in array', () => { const transformer = createInputValueTransformer( structTypeNode([ structFieldTypeNode({ name: 'id', type: numberTypeNode('u32') }), structFieldTypeNode({ name: 'items', type: arrayTypeNode( structTypeNode([ structFieldTypeNode({ name: 'name', type: stringTypeNode('utf8') }), structFieldTypeNode({ name: 'data', type: bytesTypeNode() }), ]), fixedCountNode(2), ), }), ]), rootNodeMock, { bytesEncoding: 'base16' }, ); const input = { id: 123, items: [ { data: new Uint8Array([1, 2, 3]), name: 'item1' }, { data: new Uint8Array([4, 5]), name: 'item2' }, ], }; expect(transformer(input)).toEqual({ id: 123, items: [ { data: ['base16', '010203'], name: 'item1' }, { data: ['base16', '0405'], name: 'item2' }, ], }); }); test('should throw error for non-object input', () => { const transformer = createInputValueTransformer( structTypeNode([structFieldTypeNode({ name: 'data', type: bytesTypeNode() })]), rootNodeMock, { bytesEncoding: 'base16' }, ); expect(() => transformer(null)).toThrow(/Expected \[object\] for \[structTypeNode\]/); expect(() => transformer(undefined)).toThrow(/Expected \[object\] for \[structTypeNode\]/); expect(() => transformer('not an object')).toThrow(/Expected \[object\] for \[structTypeNode\]/); expect(() => transformer(123)).toThrow(/Expected \[object\] for \[structTypeNode\]/); expect(() => transformer([1, 2, 3])).toThrow(/Expected \[object\] for \[structTypeNode\]/); }); test('should throw error for Date, Map, and Set inputs', () => { const transformer = createInputValueTransformer( structTypeNode([structFieldTypeNode({ name: 'data', type: bytesTypeNode() })]), rootNodeMock, { bytesEncoding: 'base16' }, ); expect(() => transformer(new Date())).toThrow(/Expected \[object\] for \[structTypeNode\]/); expect(() => transformer(new Map())).toThrow(/Expected \[object\] for \[structTypeNode\]/); expect(() => transformer(new Set())).toThrow(/Expected \[object\] for \[structTypeNode\]/); }); test('should transform multiple bytes fields in struct', () => { const transformer = createInputValueTransformer( structTypeNode([ structFieldTypeNode({ name: 'key', type: bytesTypeNode() }), structFieldTypeNode({ name: 'value', type: bytesTypeNode() }), structFieldTypeNode({ name: 'id', type: numberTypeNode('u32') }), ]), rootNodeMock, { bytesEncoding: 'base16' }, ); const input = { id: 999, key: new Uint8Array([1, 2]), value: new Uint8Array([3, 4, 5]), }; expect(transformer(input)).toEqual({ id: 999, key: ['base16', '0102'], value: ['base16', '030405'], }); }); test('should handle struct with missing optional fields', () => { const structNode = structTypeNode([ structFieldTypeNode({ name: 'required', type: numberTypeNode('u32') }), structFieldTypeNode({ name: 'optional', type: optionTypeNode(bytesTypeNode()) }), ]); const transformer = createInputValueTransformer(structNode, rootNodeMock, { bytesEncoding: 'base16' }); const input = { required: 100 }; expect(transformer(input)).toEqual({ required: 100 }); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/input-value-transformer/tupleTypeNode.test.ts ================================================ import { bytesTypeNode, numberTypeNode, tupleTypeNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { createInputValueTransformer } from '../../../../src/instruction-encoding/visitors/input-value-transformer'; import { rootNodeMock } from './input-value-transformer-test-utils'; describe('tupleTypeNode', () => { test('should transform each item by position', () => { const transformer = createInputValueTransformer( tupleTypeNode([numberTypeNode('u8'), bytesTypeNode()]), rootNodeMock, { bytesEncoding: 'base16' }, ); const input = [42, new Uint8Array([0xff])]; expect(transformer(input)).toEqual([42, ['base16', 'ff']]); }); test('should throw for non-array input', () => { const transformer = createInputValueTransformer(tupleTypeNode([numberTypeNode('u8')]), rootNodeMock); expect(() => transformer('not an array')).toThrow(/Expected \[array\] for \[tupleTypeNode\]/); }); test('should throw for wrong length', () => { const transformer = createInputValueTransformer( tupleTypeNode([numberTypeNode('u8'), numberTypeNode('u16')]), rootNodeMock, ); expect(() => transformer([1])).toThrow(/Expected \[array\(length:2\)\] for \[tupleTypeNode\]/); expect(() => transformer([1, 2, 3])).toThrow(/Expected \[array\(length:2\)\] for \[tupleTypeNode\]/); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/input-value-transformer/zeroableOptionTypeNode.test.ts ================================================ import { bytesTypeNode, zeroableOptionTypeNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { createInputValueTransformer } from '../../../../src/instruction-encoding/visitors/input-value-transformer'; import { rootNodeMock } from './input-value-transformer-test-utils'; describe('zeroableOptionTypeNode', () => { test('should pass through null and undefined', () => { const transformer = createInputValueTransformer(zeroableOptionTypeNode(bytesTypeNode()), rootNodeMock); expect(transformer(null)).toBe(null); expect(transformer(undefined)).toBe(undefined); }); test('should transform non-null inner value', () => { const transformer = createInputValueTransformer(zeroableOptionTypeNode(bytesTypeNode()), rootNodeMock, { bytesEncoding: 'base16', }); expect(transformer(new Uint8Array([0xcd]))).toEqual(['base16', 'cd']); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/pda-seed-value/accountValueNode.test.ts ================================================ import { address, getAddressEncoder } from '@solana/addresses'; import { accountValueNode, instructionAccountNode, instructionNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../../../svm-test-context'; import { makeVisitor } from './pda-seed-value-test-utils'; describe('pda-seed-value: visitAccountValue', () => { const ixNodeWithAccount = instructionNode({ accounts: [ instructionAccountNode({ isSigner: false, isWritable: false, name: 'authority', }), ], name: 'testInstruction', }); test('should encode provided account address', async () => { const randomAddress = await new SvmTestContext().createAccount(); const visitor = makeVisitor({ accountsInput: { authority: randomAddress }, ixNode: ixNodeWithAccount, }); const result = await visitor.visitAccountValue(accountValueNode('authority')); expect(result).toEqual(getAddressEncoder().encode(address(randomAddress))); }); test('should fall through to resolution when provided address is null', async () => { const visitor = makeVisitor({ accountsInput: { authority: null }, ixNode: ixNodeWithAccount, }); // null is not treated as a provided address — it falls through to resolveAccountAddress, // which throws because the account has no default value await expect(visitor.visitAccountValue(accountValueNode('authority'))).rejects.toThrow( /Missing account \[authority\]/, ); }); test('should throw when resolved address is null', async () => { const ixNodeWithOptionalAccount = instructionNode({ accounts: [ instructionAccountNode({ isOptional: true, isSigner: false, isWritable: false, name: 'authority', }), ], name: 'testInstruction', optionalAccountStrategy: 'omitted', }); const visitor = makeVisitor({ accountsInput: { authority: null }, ixNode: ixNodeWithOptionalAccount, }); await expect(visitor.visitAccountValue(accountValueNode('authority'))).rejects.toThrow( /Failed to derive PDA for account \[authority\]/, ); }); test('should throw for unknown account reference', async () => { const visitor = makeVisitor({ ixNode: ixNodeWithAccount }); await expect(visitor.visitAccountValue(accountValueNode('nonexistent'))).rejects.toThrow( /Referenced node \[nonexistent\] not found in \[testInstruction\]/, ); }); test('should throw on circular dependency', async () => { const visitor = makeVisitor({ ixNode: ixNodeWithAccount, resolutionPath: ['authority'], }); await expect(visitor.visitAccountValue(accountValueNode('authority'))).rejects.toThrow( /Circular dependency detected: \[/, ); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/pda-seed-value/argumentValueNode.test.ts ================================================ import { getUtf8Codec } from '@solana/codecs'; import { argumentValueNode, instructionArgumentNode, instructionNode, numberTypeNode, publicKeyTypeNode, remainderOptionTypeNode, sizePrefixTypeNode, stringTypeNode, } from 'codama'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../../../svm-test-context'; import { makeVisitor } from './pda-seed-value-test-utils'; describe('pda-seed-value: visitArgumentValue', () => { const ixNodeWithArg = instructionNode({ arguments: [instructionArgumentNode({ name: 'title', type: stringTypeNode('utf8') })], name: 'testInstruction', }); test('should encode argument value using its codec', async () => { const visitor = makeVisitor({ argumentsInput: { title: 'hello' }, ixNode: ixNodeWithArg, }); const result = await visitor.visitArgumentValue(argumentValueNode('title')); expect(result).toEqual(getUtf8Codec().encode('hello')); }); test('should use seedTypeNode override instead of argument type', async () => { // Argument type is sizePrefixTypeNode (u32 length prefix + utf8 string), // but seedTypeNode overrides it to plain stringTypeNode (raw utf8 bytes only). // This mirrors how on-chain PDA derivation uses raw string bytes as seeds, // even when the instruction argument is serialized with a length prefix. const sizePrefixedArgType = sizePrefixTypeNode(stringTypeNode('utf8'), numberTypeNode('u32')); const ixNodeWithSizePrefixedArg = instructionNode({ arguments: [instructionArgumentNode({ name: 'name', type: sizePrefixedArgType })], name: 'testInstruction', }); const visitor = makeVisitor({ argumentsInput: { name: 'hello' }, ixNode: ixNodeWithSizePrefixedArg, seedTypeNode: stringTypeNode('utf8'), }); const result = await visitor.visitArgumentValue(argumentValueNode('name')); // Should produce raw utf8 bytes (5 bytes), NOT size-prefixed bytes (4 + 5 = 9 bytes) const rawUtf8Bytes = getUtf8Codec().encode('hello'); expect(result).toEqual(rawUtf8Bytes); expect(result.length).toBe(5); }); test('should throw for unknown argument name', async () => { const visitor = makeVisitor({ ixNode: ixNodeWithArg }); await expect(visitor.visitArgumentValue(argumentValueNode('unknown'))).rejects.toThrow( /Referenced node \[unknown\] not found in \[testInstruction\]/, ); }); test('should throw when required argument value is undefined', async () => { const visitor = makeVisitor({ argumentsInput: {}, ixNode: ixNodeWithArg, }); await expect(visitor.visitArgumentValue(argumentValueNode('title'))).rejects.toThrow( /Missing argument \[title\]/, ); }); test('should throw when required argument value is null', async () => { const visitor = makeVisitor({ argumentsInput: { title: null }, ixNode: ixNodeWithArg, }); await expect(visitor.visitArgumentValue(argumentValueNode('title'))).rejects.toThrow( /Missing argument \[title\]/, ); }); describe('remainderOptionTypeNode seeds', () => { // Mirrors the pmp IDL's metadata PDA: // the "authority" seed is remainderOptionTypeNode(publicKeyTypeNode) — null is canonical. const ixNodeWithOptionalSeed = instructionNode({ arguments: [ instructionArgumentNode({ name: 'authority', type: remainderOptionTypeNode(publicKeyTypeNode()), }), ], name: 'testInstruction', }); test('should return empty bytes when argument is undefined', async () => { const visitor = makeVisitor({ argumentsInput: {}, ixNode: ixNodeWithOptionalSeed, }); const result = await visitor.visitArgumentValue(argumentValueNode('authority')); expect(result).toEqual(new Uint8Array(0)); }); test('should return empty bytes when argument is null', async () => { const visitor = makeVisitor({ argumentsInput: { authority: null }, ixNode: ixNodeWithOptionalSeed, }); const result = await visitor.visitArgumentValue(argumentValueNode('authority')); expect(result).toEqual(new Uint8Array(0)); }); test('should encode value when argument is provided', async () => { const authority = await SvmTestContext.generateAddress(); const visitor = makeVisitor({ argumentsInput: { authority }, ixNode: ixNodeWithOptionalSeed, }); const result = await visitor.visitArgumentValue(argumentValueNode('authority')); expect(result.length).toBe(32); }); test('should return empty bytes when seedTypeNode override is remainderOptionTypeNode and argument is null', async () => { const ixNodeWithRequiredArg = instructionNode({ arguments: [instructionArgumentNode({ name: 'authority', type: publicKeyTypeNode() })], name: 'testInstruction', }); const visitor = makeVisitor({ argumentsInput: { authority: null }, ixNode: ixNodeWithRequiredArg, seedTypeNode: remainderOptionTypeNode(publicKeyTypeNode()), }); const result = await visitor.visitArgumentValue(argumentValueNode('authority')); expect(result).toEqual(new Uint8Array(0)); }); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/pda-seed-value/booleanValueNode.test.ts ================================================ import { getBooleanCodec } from '@solana/codecs'; import { booleanValueNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { makeVisitor } from './pda-seed-value-test-utils'; describe('pda-seed-value: visitBooleanValue', () => { test('should encode true', async () => { const result = await makeVisitor().visitBooleanValue(booleanValueNode(true)); expect(result).toEqual(getBooleanCodec().encode(true)); }); test('should encode false', async () => { const result = await makeVisitor().visitBooleanValue(booleanValueNode(false)); expect(result).toEqual(getBooleanCodec().encode(false)); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/pda-seed-value/bytesValueNode.test.ts ================================================ import { getBase16Codec, getBase58Codec, getUtf8Codec } from '@solana/codecs'; import { bytesValueNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../../../svm-test-context'; import { makeVisitor } from './pda-seed-value-test-utils'; describe('pda-seed-value: visitBytesValue', () => { test('should encode base16 data', async () => { // const hex = Buffer.from('Hello', 'utf8').toString('hex'); const hex = '48656c6c6f'; const result = await makeVisitor().visitBytesValue(bytesValueNode('base16', hex)); expect(result).toEqual(getBase16Codec().encode(hex)); }); test('should encode base58 data', async () => { const b58 = await new SvmTestContext().createAccount(); const result = await makeVisitor().visitBytesValue(bytesValueNode('base58', b58)); expect(result).toEqual(getBase58Codec().encode(b58)); }); test('should encode utf8 data', async () => { const text = 'Hello'; const result = await makeVisitor().visitBytesValue(bytesValueNode('utf8', text)); expect(result).toEqual(getUtf8Codec().encode(text)); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/pda-seed-value/constantValueNode.test.ts ================================================ import { getUtf8Codec } from '@solana/codecs'; import { constantValueNode, mapValueNode, numberTypeNode, stringTypeNode, stringValueNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { PDA_SEED_VALUE_SUPPORTED_NODE_KINDS } from '../../../../src/instruction-encoding/visitors/pda-seed-value'; import { makeVisitor } from './pda-seed-value-test-utils'; describe('pda-seed-value: visitConstantValue', () => { test('should delegate to inner stringValueNode', async () => { const node = constantValueNode(stringTypeNode('utf8'), stringValueNode('Hello world')); const result = await makeVisitor().visitConstantValue(node); expect(result).toEqual(getUtf8Codec().encode('Hello world')); }); test('should delegate to nested inner constantValueNode', async () => { const node = constantValueNode( stringTypeNode('utf8'), constantValueNode(stringTypeNode('utf8'), stringValueNode('Nested hello world')), ); const result = await makeVisitor().visitConstantValue(node); expect(result).toEqual(getUtf8Codec().encode('Nested hello world')); }); test('should throw for unsupported inner node kind', async () => { const node = constantValueNode(numberTypeNode('u8'), mapValueNode([])); await expect(makeVisitor().visitConstantValue(node)).rejects.toThrow( `Expected node of kind [${PDA_SEED_VALUE_SUPPORTED_NODE_KINDS.join(',')}], got [mapValueNode]`, ); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/pda-seed-value/noneValueNode.test.ts ================================================ import { noneValueNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { makeVisitor } from './pda-seed-value-test-utils'; describe('pda-seed-value: visitNoneValue', () => { test('should return empty Uint8Array', async () => { const result = await makeVisitor().visitNoneValue(noneValueNode()); expect(result).toEqual(new Uint8Array(0)); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/pda-seed-value/numberValueNode.test.ts ================================================ import { CodamaError } from '@codama/errors'; import { numberValueNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { makeVisitor } from './pda-seed-value-test-utils'; describe('pda-seed-value: visitNumberValue', () => { test('should encode 0 as single byte', async () => { const result = await makeVisitor().visitNumberValue(numberValueNode(0)); expect(result).toEqual(new Uint8Array([0])); }); test('should encode 255 as single byte', async () => { const result = await makeVisitor().visitNumberValue(numberValueNode(255)); expect(result).toEqual(new Uint8Array([255])); }); test('should throw for value > 255', async () => { await expect(makeVisitor().visitNumberValue(numberValueNode(256))).rejects.toThrow(/out of range/); }); test('should throw for negative value', async () => { await expect(makeVisitor().visitNumberValue(numberValueNode(-1))).rejects.toThrow(CodamaError); }); test('should throw for non-integer value', async () => { await expect(makeVisitor().visitNumberValue(numberValueNode(1.5))).rejects.toThrow(/out of range/); }); test('should throw for large value', async () => { await expect(makeVisitor().visitNumberValue(numberValueNode(70000))).rejects.toThrow(/out of range/); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/pda-seed-value/pda-seed-value-test-utils.ts ================================================ import { address } from '@solana/addresses'; import { instructionNode, programNode, rootNode } from 'codama'; import { createPdaSeedValueVisitor } from '../../../../src/instruction-encoding/visitors/pda-seed-value'; const PROGRAM_PUBLIC_KEY = '11111111111111111111111111111111'; export const rootNodeMock = rootNode(programNode({ name: 'test', publicKey: PROGRAM_PUBLIC_KEY })); export const ixNodeStub = instructionNode({ name: 'testInstruction' }); export function makeVisitor(overrides?: Partial[0]>) { return createPdaSeedValueVisitor({ accountsInput: undefined, argumentsInput: undefined, ixNode: ixNodeStub, programId: address(PROGRAM_PUBLIC_KEY), resolutionPath: [], resolversInput: undefined, root: rootNodeMock, ...overrides, }); } ================================================ FILE: packages/dynamic-client/test/unit/visitors/pda-seed-value/programIdValueNode.test.ts ================================================ import { getAddressEncoder } from '@solana/addresses'; import { programIdValueNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../../../svm-test-context'; import { makeVisitor } from './pda-seed-value-test-utils'; describe('pda-seed-value: visitProgramIdValue', () => { test('should encode the context programId as 32-byte address', async () => { const svm = new SvmTestContext(); const randomAddress = await svm.createAccount(); const result = await makeVisitor({ programId: randomAddress, }).visitProgramIdValue(programIdValueNode()); expect(result).toEqual(getAddressEncoder().encode(randomAddress)); }); test('should throw an error for non-string programId', async () => { const invalidValues = [42, [1, 2, 3], null]; for (const value of invalidValues) { // @ts-expect-error testing invalid programId value const visitor = makeVisitor({ programId: value }); await expect(visitor.visitProgramIdValue(programIdValueNode())).rejects.toThrow( `Cannot convert value to Address: [${JSON.stringify(value)}].`, ); } }); test('should throw an error for invalid string programId', async () => { const invalidValues = ['not-a-key', '123', '', ' ']; for (const value of invalidValues) { // @ts-expect-error testing invalid programId value const visitor = makeVisitor({ programId: value }); await expect(visitor.visitProgramIdValue(programIdValueNode())).rejects.toThrow( `Cannot convert value to Address: [${JSON.stringify(value)}].`, ); } }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/pda-seed-value/publicKeyValueNode.test.ts ================================================ import { address, getAddressEncoder } from '@solana/addresses'; import { publicKeyValueNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../../../svm-test-context'; import { makeVisitor } from './pda-seed-value-test-utils'; describe('pda-seed-value: visitPublicKeyValue', () => { test('should encode the provided public key as 32-byte address', async () => { const svm = new SvmTestContext(); const randomAddress = await svm.createAccount(); const result = await makeVisitor().visitPublicKeyValue(publicKeyValueNode(randomAddress)); expect(result).toEqual(getAddressEncoder().encode(address(randomAddress))); }); test('should throw for invalid public key', async () => { const invalidPublicKeys = [123, 'not-a-key', [1, 2, 3], null]; const visitor = makeVisitor(); for (const invalidPublicKey of invalidPublicKeys) { // @ts-expect-error testing invalid inputs await expect(visitor.visitPublicKeyValue(publicKeyValueNode(invalidPublicKey))).rejects.toThrow( `Cannot convert value to Address: [${JSON.stringify(invalidPublicKey)}].`, ); } }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/pda-seed-value/someValueNode.test.ts ================================================ import { constantValueNode, mapValueNode, numberValueNode, publicKeyTypeNode, publicKeyValueNode, someValueNode, } from 'codama'; import { describe, expect, test } from 'vitest'; import { PDA_SEED_VALUE_SUPPORTED_NODE_KINDS } from '../../../../src/instruction-encoding/visitors/pda-seed-value'; import { makeVisitor } from './pda-seed-value-test-utils'; describe('pda-seed-value: visitSomeValue', () => { test('should delegate to inner numberValueNode', async () => { const node = someValueNode(numberValueNode(42)); const result = await makeVisitor().visitSomeValue(node); expect(result).toEqual(new Uint8Array([42])); }); test('should throw for unsupported inner node kind', async () => { const node = someValueNode(mapValueNode([])); await expect(makeVisitor().visitSomeValue(node)).rejects.toThrow( `Expected node of kind [${PDA_SEED_VALUE_SUPPORTED_NODE_KINDS.join(',')}], got [mapValueNode]`, ); }); test('should throw for unsupported nested inner node kind', async () => { const node = someValueNode(constantValueNode(publicKeyTypeNode(), publicKeyValueNode('invalid-key'))); await expect(makeVisitor().visitSomeValue(node)).rejects.toThrow( 'Cannot convert value to Address: ["invalid-key"].', ); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/pda-seed-value/stringValueNode.test.ts ================================================ import { getUtf8Codec } from '@solana/codecs'; import { stringValueNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { makeVisitor } from './pda-seed-value-test-utils'; describe('pda-seed-value: visitStringValue', () => { test('should encode non-empty string as UTF-8 bytes', async () => { const result = await makeVisitor().visitStringValue(stringValueNode('hello')); expect(result).toEqual(getUtf8Codec().encode('hello')); }); test('should encode empty string as empty bytes', async () => { const result = await makeVisitor().visitStringValue(stringValueNode('')); expect(result).toEqual(getUtf8Codec().encode('')); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/value-node-value/arrayValueNode.test.ts ================================================ import { accountValueNode, arrayValueNode, numberValueNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { VALUE_NODE_SUPPORTED_NODE_KINDS } from '../../../../src/instruction-encoding/visitors/value-node-value'; import { makeVisitor } from './value-node-value-test-utils'; describe('value-node-value: visitArrayValue', () => { test('should resolve empty array', () => { const result = makeVisitor().visitArrayValue(arrayValueNode([])); expect(result).toEqual({ kind: 'arrayValueNode', value: [] }); }); test('should resolve array items recursively', () => { const result = makeVisitor().visitArrayValue(arrayValueNode([numberValueNode(1), numberValueNode(2)])); expect(result).toEqual({ kind: 'arrayValueNode', value: [ { kind: 'numberValueNode', value: 1 }, { kind: 'numberValueNode', value: 2 }, ], }); }); test('should throw for unsupported inner node', () => { expect(() => makeVisitor().visitArrayValue( // @ts-expect-error - accountValueNode is invalid arrayValueNode([accountValueNode('test')]), ), ).toThrow(`Expected node of kind [${VALUE_NODE_SUPPORTED_NODE_KINDS.join(',')}], got [accountValueNode]`); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/value-node-value/booleanValueNode.test.ts ================================================ import { booleanValueNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { makeVisitor } from './value-node-value-test-utils'; describe('value-node-value: visitBooleanValue', () => { test('should resolve true', () => { const result = makeVisitor().visitBooleanValue(booleanValueNode(true)); expect(result).toEqual({ kind: 'booleanValueNode', value: true }); }); test('should resolve false', () => { const result = makeVisitor().visitBooleanValue(booleanValueNode(false)); expect(result).toEqual({ kind: 'booleanValueNode', value: false }); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/value-node-value/bytesValueNode.test.ts ================================================ import { bytesValueNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { makeVisitor } from './value-node-value-test-utils'; describe('value-node-value: visitBytesValue', () => { test('should resolve with base16 encoding', () => { const result = makeVisitor().visitBytesValue(bytesValueNode('base16', 'deadbeef')); expect(result).toEqual({ encoding: 'base16', kind: 'bytesValueNode', value: 'deadbeef' }); }); test('should resolve with base64 encoding', () => { const result = makeVisitor().visitBytesValue(bytesValueNode('base64', 'AQID')); expect(result).toEqual({ encoding: 'base64', kind: 'bytesValueNode', value: 'AQID' }); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/value-node-value/constantValueNode.test.ts ================================================ import { accountValueNode, constantValueNode, numberTypeNode, numberValueNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { VALUE_NODE_SUPPORTED_NODE_KINDS } from '../../../../src/instruction-encoding/visitors/value-node-value'; import { makeVisitor } from './value-node-value-test-utils'; describe('value-node-value: visitConstantValue', () => { test('should delegate to inner value node', () => { const result = makeVisitor().visitConstantValue(constantValueNode(numberTypeNode('u8'), numberValueNode(255))); expect(result).toEqual({ kind: 'numberValueNode', value: 255 }); }); test('should throw for unsupported inner node', () => { expect(() => makeVisitor().visitConstantValue( // @ts-expect-error - accountValueNode is invalid inside constantValueNode constantValueNode(numberTypeNode('u8'), accountValueNode('test')), ), ).toThrow(`Expected node of kind [${VALUE_NODE_SUPPORTED_NODE_KINDS.join(',')}], got [accountValueNode]`); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/value-node-value/enumValueNode.test.ts ================================================ import { enumValueNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { makeVisitor } from './value-node-value-test-utils'; describe('value-node-value: visitEnumValue', () => { test('should resolve enum variant', () => { const result = makeVisitor().visitEnumValue(enumValueNode('TokenStandard', 'nonFungible')); expect(result).toEqual({ kind: 'enumValueNode', value: 'nonFungible' }); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/value-node-value/mapValueNode.test.ts ================================================ import { accountValueNode, mapEntryValueNode, mapValueNode, numberValueNode, stringValueNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { VALUE_NODE_SUPPORTED_NODE_KINDS } from '../../../../src/instruction-encoding/visitors/value-node-value'; import { makeVisitor } from './value-node-value-test-utils'; describe('value-node-value: visitMapValue', () => { test('should resolve empty map', () => { const result = makeVisitor().visitMapValue(mapValueNode([])); expect(result).toEqual({ kind: 'mapValueNode', value: [] }); }); test('should resolve key/value pairs recursively', () => { const result = makeVisitor().visitMapValue( mapValueNode([mapEntryValueNode(stringValueNode('key1'), numberValueNode(100))]), ); expect(result).toEqual({ kind: 'mapValueNode', value: [ { key: { kind: 'stringValueNode', value: 'key1' }, value: { kind: 'numberValueNode', value: 100 }, }, ], }); }); test('should throw for unsupported map key', () => { expect(() => makeVisitor().visitMapValue( mapValueNode([ mapEntryValueNode( // @ts-expect-error - accountValueNode is invalid StandaloneValueNode accountValueNode('test'), numberValueNode(1), ), ]), ), ).toThrow(`Expected node of kind [${VALUE_NODE_SUPPORTED_NODE_KINDS.join(',')}], got [accountValueNode]`); }); test('should throw for unsupported map value', () => { expect(() => makeVisitor().visitMapValue( mapValueNode([ mapEntryValueNode( stringValueNode('ok'), // @ts-expect-error - accountValueNode is invalid StandaloneValueNode accountValueNode('test'), ), ]), ), ).toThrow(`Expected node of kind [${VALUE_NODE_SUPPORTED_NODE_KINDS.join(',')}], got [accountValueNode]`); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/value-node-value/noneValueNode.test.ts ================================================ import { noneValueNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { makeVisitor } from './value-node-value-test-utils'; describe('value-node-value: visitNoneValue', () => { test('should resolve none to null', () => { const result = makeVisitor().visitNoneValue(noneValueNode()); expect(result).toEqual({ kind: 'noneValueNode', value: null }); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/value-node-value/numberValueNode.test.ts ================================================ import { numberValueNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { makeVisitor } from './value-node-value-test-utils'; describe('value-node-value: visitNumberValue', () => { test('should resolve positive number', () => { const result = makeVisitor().visitNumberValue(numberValueNode(42)); expect(result).toEqual({ kind: 'numberValueNode', value: 42 }); }); test('should resolve zero', () => { const result = makeVisitor().visitNumberValue(numberValueNode(0)); expect(result).toEqual({ kind: 'numberValueNode', value: 0 }); }); test('should resolve negative number', () => { const result = makeVisitor().visitNumberValue(numberValueNode(-7)); expect(result).toEqual({ kind: 'numberValueNode', value: -7 }); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/value-node-value/publicKeyValueNode.test.ts ================================================ import { address } from '@solana/addresses'; import { publicKeyValueNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { SvmTestContext } from '../../../svm-test-context'; import { makeVisitor } from './value-node-value-test-utils'; describe('value-node-value: visitPublicKeyValue', () => { test('should resolve to Address', async () => { const key = await SvmTestContext.generateAddress(); const result = makeVisitor().visitPublicKeyValue(publicKeyValueNode(key)); expect(result).toEqual({ kind: 'publicKeyValueNode', value: address(key) }); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/value-node-value/setValueNode.test.ts ================================================ import { accountValueNode, numberValueNode, setValueNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { VALUE_NODE_SUPPORTED_NODE_KINDS } from '../../../../src/instruction-encoding/visitors/value-node-value'; import { makeVisitor } from './value-node-value-test-utils'; describe('value-node-value: visitSetValue', () => { test('should resolve empty set', () => { const result = makeVisitor().visitSetValue(setValueNode([])); expect(result).toEqual({ kind: 'setValueNode', value: [] }); }); test('should resolve set items', () => { const result = makeVisitor().visitSetValue(setValueNode([numberValueNode(10), numberValueNode(20)])); expect(result).toEqual({ kind: 'setValueNode', value: [ { kind: 'numberValueNode', value: 10 }, { kind: 'numberValueNode', value: 20 }, ], }); }); test('should throw for unsupported inner node', () => { expect(() => makeVisitor().visitSetValue( // @ts-expect-error - accountValueNode is invalid as StandaloneValueNode setValueNode([accountValueNode('test')]), ), ).toThrow(`Expected node of kind [${VALUE_NODE_SUPPORTED_NODE_KINDS.join(',')}], got [accountValueNode]`); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/value-node-value/someValueNode.test.ts ================================================ import { accountValueNode, numberValueNode, someValueNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { VALUE_NODE_SUPPORTED_NODE_KINDS } from '../../../../src/instruction-encoding/visitors/value-node-value'; import { makeVisitor } from './value-node-value-test-utils'; describe('value-node-value: visitSomeValue', () => { test('should delegate to inner value node', () => { const result = makeVisitor().visitSomeValue(someValueNode(numberValueNode(42))); expect(result).toEqual({ kind: 'numberValueNode', value: 42 }); }); test('should throw for unsupported inner node', () => { expect(() => makeVisitor().visitSomeValue( // @ts-expect-error - accountValueNode is invalid someValueNode(accountValueNode('test')), ), ).toThrow(`Expected node of kind [${VALUE_NODE_SUPPORTED_NODE_KINDS.join(',')}], got [accountValueNode]`); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/value-node-value/stringValueNode.test.ts ================================================ import { stringValueNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { makeVisitor } from './value-node-value-test-utils'; describe('value-node-value: visitStringValue', () => { test('should resolve string', () => { const result = makeVisitor().visitStringValue(stringValueNode('hello')); expect(result).toEqual({ kind: 'stringValueNode', value: 'hello' }); }); test('should resolve empty string', () => { const result = makeVisitor().visitStringValue(stringValueNode('')); expect(result).toEqual({ kind: 'stringValueNode', value: '' }); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/value-node-value/structValueNode.test.ts ================================================ import { accountValueNode, numberValueNode, stringValueNode, structFieldValueNode, structValueNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { VALUE_NODE_SUPPORTED_NODE_KINDS } from '../../../../src/instruction-encoding/visitors/value-node-value'; import { makeVisitor } from './value-node-value-test-utils'; describe('value-node-value: visitStructValue', () => { test('should resolve struct fields to object entries', () => { const result = makeVisitor().visitStructValue( structValueNode([ structFieldValueNode('name', stringValueNode('Alice')), structFieldValueNode('age', numberValueNode(30)), ]), ); expect(result).toEqual({ kind: 'structValueNode', value: { age: { kind: 'numberValueNode', value: 30 }, name: { kind: 'stringValueNode', value: 'Alice' }, }, }); }); test('should throw for unsupported field value', () => { expect(() => makeVisitor().visitStructValue( // @ts-expect-error - accountValueNode is invalid as a StandaloneValueNode structValueNode([structFieldValueNode('invalid_field', accountValueNode('test'))]), ), ).toThrow(`Expected node of kind [${VALUE_NODE_SUPPORTED_NODE_KINDS.join(',')}], got [accountValueNode]`); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/value-node-value/tupleValueNode.test.ts ================================================ import { accountValueNode, booleanValueNode, numberValueNode, stringValueNode, tupleValueNode } from 'codama'; import { describe, expect, test } from 'vitest'; import { VALUE_NODE_SUPPORTED_NODE_KINDS } from '../../../../src/instruction-encoding/visitors/value-node-value'; import { makeVisitor } from './value-node-value-test-utils'; describe('value-node-value: visitTupleValue', () => { test('should resolve mixed-type tuple items', () => { const result = makeVisitor().visitTupleValue( tupleValueNode([numberValueNode(1), stringValueNode('a'), booleanValueNode(true)]), ); expect(result).toEqual({ kind: 'tupleValueNode', value: [ { kind: 'numberValueNode', value: 1 }, { kind: 'stringValueNode', value: 'a' }, { kind: 'booleanValueNode', value: true }, ], }); }); test('should throw for unsupported inner node', () => { expect(() => makeVisitor().visitTupleValue( // @ts-expect-error - accountValueNode is invalid as a StandaloneValueNode tupleValueNode([accountValueNode('test')]), ), ).toThrow(`Expected node of kind [${VALUE_NODE_SUPPORTED_NODE_KINDS.join(',')}], got [accountValueNode]`); }); }); ================================================ FILE: packages/dynamic-client/test/unit/visitors/value-node-value/value-node-value-test-utils.ts ================================================ import { createValueNodeVisitor } from '../../../../src/instruction-encoding/visitors/value-node-value'; export function makeVisitor() { return createValueNodeVisitor(); } ================================================ FILE: packages/dynamic-client/tsconfig.declarations.json ================================================ { "compilerOptions": { "declaration": true, "declarationMap": true, "emitDeclarationOnly": true, "outDir": "./dist/types" }, "extends": "./tsconfig.json", "include": ["src/index.ts", "src/types"] } ================================================ FILE: packages/dynamic-client/tsconfig.json ================================================ { "$schema": "https://json.schemastore.org/tsconfig", "compilerOptions": { "lib": ["ES2022.Object", "ES2022.Error"] }, "display": "@codama/dynamic-client", "extends": "../../tsconfig.json", "include": ["src", "test"] } ================================================ FILE: packages/dynamic-client/tsup.cli.config.ts ================================================ import { defineConfig } from 'tsup'; import { getCliBuildConfig } from '../../tsup.config.base'; export default defineConfig([getCliBuildConfig()]); ================================================ FILE: packages/dynamic-client/tsup.config.ts ================================================ import { defineConfig } from 'tsup'; import { getCliBuildConfig, getPackageBuildConfigs } from '../../tsup.config.base'; export default defineConfig([...getPackageBuildConfigs(), getCliBuildConfig()]); ================================================ FILE: packages/dynamic-client/vitest.config.mts ================================================ import { defineConfig } from 'vitest/config'; import { getVitestConfig } from '../../vitest.config.base.mjs'; export default defineConfig({ test: { projects: [getVitestConfig('browser'), getVitestConfig('node'), getVitestConfig('react-native')], }, }); ================================================ FILE: packages/dynamic-codecs/.gitignore ================================================ dist/ ================================================ FILE: packages/dynamic-codecs/.prettierignore ================================================ dist/ test/e2e/ test-ledger/ target/ CHANGELOG.md ================================================ FILE: packages/dynamic-codecs/LICENSE ================================================ MIT License Copyright (c) 2025 Codama Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: packages/dynamic-codecs/README.md ================================================ # Codama ➤ Dynamic Codecs [![npm][npm-image]][npm-url] [![npm-downloads][npm-downloads-image]][npm-url] [npm-downloads-image]: https://img.shields.io/npm/dm/@codama/dynamic-codecs.svg?style=flat [npm-image]: https://img.shields.io/npm/v/@codama/dynamic-codecs.svg?style=flat&label=%40codama%2Fdynamic-codecs [npm-url]: https://www.npmjs.com/package/@codama/dynamic-codecs This package provides a set of helpers that provide `Codecs` for Codama nodes that describe data. ## Installation ```sh pnpm install @codama/dynamic-codecs ``` > [!NOTE] > This package is **not** included in the main [`codama`](../library) package. ## Functions ### `getNodeCodec(path, options?)` Given the full `NodePath` of a node inside a Codama IDL, returns a `Codec` (as defined in `@solana/codecs`) that enables encoding and decoding data for that node. ```ts const codec = getNodeCodec([root, program, definedType]); const bytes = codec.encode(someData); const decodedData = codec.decode(bytes); ``` Note that it is important to provide the full `NodePath` of the node in order to properly follow link nodes inside the Codama IDL. Here is a more complex example illustrating how link nodes are resolved: ```ts // Here we define a program with two types, one of which is a link to the other. const root = rootNode( programNode({ definedTypes: [ definedTypeNode({ name: 'slot', type: numberTypeNode('u64') }), definedTypeNode({ name: 'lastSlot', type: definedTypeLinkNode('slot') }), ], name: 'myProgram', publicKey: '1111', }), ); // The codec for the linked `lastSlot` defined type is resolved using the `slot` defined type. const codec = getNodeCodec([root, root.program, root.program.definedTypes[1]]); expect(codec.encode(42)).toStrictEqual(hex('2a00000000000000')); expect(codec.decode(hex('2a00000000000000'))).toBe(42n); ``` #### Options The `getNodeCodec` function accepts the following options. | Name | Type | Default | Description | | --------------- | --------------- | ---------- | -------------------------------------------------------- | | `bytesEncoding` | `BytesEncoding` | `"base64"` | The default encoding to use when formatting plain bytes. | #### Decoded format In the table below, we illustrate the format of each codec based on the node from which it was created. Note that we purposefully avoid types such as `Uint8Array`, `Set` or `Map` in order to keep the format JSON compatible. For instance, plain bytes are not provided as `Uint8Array` but as a tuple of type `[BytesEncoding, string]` — e.g. `["base64", "HelloWorld++"]` — where the default bytes encoding is `base64` which is configurable via the `bytesEncoding` option. | Node | Example | Notes | | --------------------------------------------------------------------------------------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------- | | [`AccountLinkNode`](../nodes/docs/linkNodes/AccountLinkNode.md) | - | Same as `AccountNode` | | [`AccountNode`](../nodes/docs/AccountNode.md) | - | Same as `node.data` | | [`DefinedTypeLinkNode`](../nodes/docs/linkNodes/DefinedTypeLinkNode.md) | - | Same as `DefinedTypeNode` | | [`DefinedTypeNode`](../nodes/docs/DefinedTypeNode.md) | - | Same as `node.type` | | [`InstructionArgumentLinkNode`](../nodes/docs/linkNodes/InstructionArgumentLinkNode.md) | - | Same as `InstructionArgumentNode` | | [`InstructionArgumentNode`](../nodes/docs/InstructionArgumentNode.md) | - | Same as `node.type` | | [`InstructionLinkNode`](../nodes/docs/linkNodes/InstructionLinkNode.md) | - | Same as `InstructionNode` | | [`InstructionNode`](../nodes/docs/InstructionNode.md) | - | Same as a `StructTypeNode` containing all `node.arguments` | | [`AmountTypeNode`](../nodes/docs/typeNodes/AmountTypeNode.md) | `42` | Same as `NumberTypeNode` | | [`ArrayTypeNode`](../nodes/docs/typeNodes/ArrayTypeNode.md) | `[1, 2, 3]` | | | [`BooleanTypeNode`](../nodes/docs/typeNodes/BooleanTypeNode.md) | `true` or `false` | | | [`BytesTypeNode`](../nodes/docs/typeNodes/BytesTypeNode.md) | `["base16", "00ffaa"]` | Uses `bytesEncoding` option to decode | | [`DateTimeTypeNode`](../nodes/docs/typeNodes/DateTimeTypeNode.md) | `42` | Same as `NumberTypeNode` | | [`EnumTypeNode`](../nodes/docs/typeNodes/EnumTypeNode.md) | `2` or `{ __kind: "move", x: 12, y: 34 }` | Uses number indices for scalar enums. Uses discriminated unions otherwise. | | [`FixedSizeTypeNode`](../nodes/docs/typeNodes/FixedSizeTypeNode.md) | - | Same as `node.type` | | [`HiddenPrefixTypeNode`](../nodes/docs/typeNodes/HiddenPrefixTypeNode.md) | - | Same as `node.type` | | [`HiddenSuffixTypeNode`](../nodes/docs/typeNodes/HiddenSuffixTypeNode.md) | - | Same as `node.type` | | [`MapTypeNode`](../nodes/docs/typeNodes/MapTypeNode.md) | `{ key1: "value1", key2: "value2" }` | Represent `Maps` as `objects` | | [`NumberTypeNode`](../nodes/docs/typeNodes/NumberTypeNode.md) | `42` | This could be a `bigint` | | [`OptionTypeNode`](../nodes/docs/typeNodes/OptionTypeNode.md) | `{ __option: "Some", value: 42 }` or `{ __option: "None" }` | Uses value objects (instead of `T \| null`) to avoid loosing information on nested options. | | [`PostOffsetTypeNode`](../nodes/docs/typeNodes/PostOffsetTypeNode.md) | - | Same as `node.type` | | [`PreOffsetTypeNode`](../nodes/docs/typeNodes/PreOffsetTypeNode.md) | - | Same as `node.type` | | [`PublicKeyTypeNode`](../nodes/docs/typeNodes/PublicKeyTypeNode.md) | `"3QC7Pnv2KfwwdC44gPcmQWuZXmRSbUpmWMJnhenMC8CU"` | Uses base58 representations of public keys | | [`RemainderOptionTypeNode`](../nodes/docs/typeNodes/RemainderOptionTypeNode.md) | `{ __option: "Some", value: 42 }` or `{ __option: "None" }` | Same as `OptionTypeNode` | | [`SentinelTypeNode`](../nodes/docs/typeNodes/SentinelTypeNode.md) | - | Same as `node.type` | | [`SetTypeNode`](../nodes/docs/typeNodes/SetTypeNode.md) | `[1, 2, 3]` | Same as `ArrayTypeNode` | | [`SizePrefixTypeNode`](../nodes/docs/typeNodes/SizePrefixTypeNode.md) | - | Same as `node.type` | | [`SolAmountTypeNode`](../nodes/docs/typeNodes/SolAmountTypeNode.md) | `42` | Same as `NumberTypeNode` | | [`StringTypeNode`](../nodes/docs/typeNodes/StringTypeNode.md) | `"Hello World"` | Uses the encoding defined in the node — i.e. `node.encoding` | | [`StructTypeNode`](../nodes/docs/typeNodes/StructTypeNode.md) | `{ name: "John", age: 42 }` | | | [`TupleTypeNode`](../nodes/docs/typeNodes/TupleTypeNode.md) | `["John", 42]` | Uses arrays to create tuples | | [`ZeroableOptionTypeNode`](../nodes/docs/typeNodes/ZeroableOptionTypeNode.md) | `{ __option: "Some", value: 42 }` or `{ __option: "None" }` | Same as `OptionTypeNode` | ### `getNodeCodecVisitor(linkables, options?)` This visitor is used by `getNodeCodec` under the hood. It returns a `Codec` for the visited node. ```ts return visit(someTypeNode, getNodeCodecVisitor(linkables)); ``` ### `getValueNodeVisitor(linkables, options?)` This visitor is used by the `getValueNodeVisitor` under the hood. It returns an `unknown` value for the visited `ValueNode`. ```ts return visit(someValueNode, getValueNodeVisitor(linkables)); ``` ================================================ FILE: packages/dynamic-codecs/package.json ================================================ { "name": "@codama/dynamic-codecs", "version": "1.2.0", "description": "Get codecs on demand for Codama IDLs", "exports": { "types": "./dist/types/index.d.ts", "react-native": "./dist/index.react-native.mjs", "browser": { "import": "./dist/index.browser.mjs", "require": "./dist/index.browser.cjs" }, "node": { "import": "./dist/index.node.mjs", "require": "./dist/index.node.cjs" } }, "browser": { "./dist/index.node.cjs": "./dist/index.browser.cjs", "./dist/index.node.mjs": "./dist/index.browser.mjs" }, "main": "./dist/index.node.cjs", "module": "./dist/index.node.mjs", "react-native": "./dist/index.react-native.mjs", "types": "./dist/types/index.d.ts", "type": "commonjs", "files": [ "./dist/types", "./dist/index.*" ], "sideEffects": false, "keywords": [ "solana", "framework", "standard", "specifications", "codecs" ], "scripts": { "build": "rimraf dist && tsup && tsc -p ./tsconfig.declarations.json", "dev": "vitest --project node", "lint": "eslint . && prettier --check .", "lint:fix": "eslint --fix . && prettier --write .", "test": "pnpm test:types && pnpm test:treeshakability && pnpm test:unit", "test:treeshakability": "for file in dist/index.*.mjs; do agadoo $file; done", "test:types": "tsc --noEmit", "test:unit": "vitest run" }, "dependencies": { "@codama/errors": "workspace:*", "@codama/nodes": "workspace:*", "@codama/visitors-core": "workspace:*", "@solana/codecs": "^5.3.0" }, "license": "MIT", "repository": { "type": "git", "url": "https://github.com/codama-idl/codama" }, "bugs": { "url": "http://github.com/codama-idl/codama/issues" }, "browserslist": [ "supports bigint and not dead", "maintained node versions" ] } ================================================ FILE: packages/dynamic-codecs/src/codecs.ts ================================================ import { CODAMA_ERROR__UNRECOGNIZED_BYTES_ENCODING, CODAMA_ERROR__UNRECOGNIZED_NUMBER_FORMAT, CodamaError, } from '@codama/errors'; import { AccountLinkNode, AccountNode, BytesEncoding, CountNode, DefinedTypeLinkNode, DefinedTypeNode, EventNode, InstructionArgumentLinkNode, InstructionArgumentNode, InstructionLinkNode, InstructionNode, isNode, isScalarEnum, NumberFormat, pascalCase, RegisteredTypeNode, structFieldTypeNode, structFieldTypeNodeFromInstructionArgumentNode, structTypeNode, structTypeNodeFromInstructionArgumentNodes, } from '@codama/nodes'; import { getLastNodeFromPath, getRecordLinkablesVisitor, LinkableDictionary, NodePath, NodeStack, pipe, recordNodeStackVisitor, visit, Visitor, } from '@codama/visitors-core'; import { addCodecSentinel, addCodecSizePrefix, assertIsFixedSize, Codec, createCodec, fixCodecSize, getArrayCodec, getBase16Codec, getBase58Codec, getBase64Codec, getBooleanCodec, getConstantCodec, getDiscriminatedUnionCodec, getEnumCodec, getF32Codec, getF64Codec, getHiddenPrefixCodec, getHiddenSuffixCodec, getI8Codec, getI16Codec, getI32Codec, getI64Codec, getI128Codec, getMapCodec, getOptionCodec, getShortU16Codec, getStructCodec, getTupleCodec, getU8Codec, getU16Codec, getU32Codec, getU64Codec, getU128Codec, getUnitCodec, getUtf8Codec, NumberCodec, offsetCodec, padLeftCodec, padRightCodec, transformCodec, } from '@solana/codecs'; import { getValueNodeVisitor } from './values'; export type EncodableNodes = | AccountLinkNode | AccountNode | DefinedTypeLinkNode | DefinedTypeNode | EventNode | InstructionArgumentLinkNode | InstructionArgumentNode | InstructionLinkNode | InstructionNode | RegisteredTypeNode; export type CodecVisitorOptions = { bytesEncoding?: BytesEncoding; }; export function getNodeCodec(path: NodePath, options: CodecVisitorOptions = {}): Codec { const linkables = new LinkableDictionary(); visit(path[0], getRecordLinkablesVisitor(linkables)); return visit( getLastNodeFromPath(path), getNodeCodecVisitor(linkables, { stack: new NodeStack(path.slice(0, -1)), ...options, }), ); } export function getNodeCodecVisitor( linkables: LinkableDictionary, options: CodecVisitorOptions & { stack?: NodeStack } = {}, ): Visitor, EncodableNodes['kind']> { const stack = options.stack ?? new NodeStack(); const bytesEncoding = options.bytesEncoding ?? 'base64'; const valueNodeVisitor = getValueNodeVisitor(linkables, { codecVisitorFactory: () => visitor, stack, }); const baseVisitor: Visitor, EncodableNodes['kind']> = { visitAccount(node) { return visit(node.data, this); }, visitAccountLink(node) { const path = linkables.getPathOrThrow(stack.getPath(node.kind)); stack.pushPath(path); const result = visit(getLastNodeFromPath(path), this); stack.popPath(); return result; }, visitAmountType(node) { return visit(node.number, this); }, visitArrayType(node) { const item = visit(node.item, this); const size = getSizeFromCountNode(node.count, this); return getArrayCodec(item, { size }) as Codec; }, visitBooleanType(node) { const size = visit(node.size, this) as NumberCodec; return getBooleanCodec({ size }) as Codec; }, visitBytesType() { // Note we use a format like `["base64", "someData"]` to encode bytes, // instead of using `Uint8Arrays` in order to be compatible with JSON. return createCodec<[BytesEncoding, string]>({ getSizeFromValue: ([encoding, value]) => { return getCodecFromBytesEncoding(encoding).getSizeFromValue(value); }, read: (bytes, offset) => { const [value, newOffset] = getCodecFromBytesEncoding(bytesEncoding).read(bytes, offset); return [[bytesEncoding, value], newOffset]; }, write: ([encoding, value], bytes, offset) => { return getCodecFromBytesEncoding(encoding).write(value, bytes, offset); }, }) as Codec; }, visitDateTimeType(node) { return visit(node.number, this); }, visitDefinedType(node) { return visit(node.type, this); }, visitDefinedTypeLink(node) { const path = linkables.getPathOrThrow(stack.getPath(node.kind)); stack.pushPath(path); const result = visit(getLastNodeFromPath(path), this); stack.popPath(); return result; }, visitEnumEmptyVariantType() { return getUnitCodec() as Codec; }, visitEnumStructVariantType(node) { return visit(node.struct, this); }, visitEnumTupleVariantType(node) { const tupleAsStruct = structTypeNode([structFieldTypeNode({ name: 'fields', type: node.tuple })]); return visit(tupleAsStruct, this); }, visitEnumType(node) { const size = visit(node.size, this) as NumberCodec; // Scalar enums are decoded as simple numbers. if (isScalarEnum(node)) { return getEnumCodec( Object.fromEntries( node.variants.flatMap((variant, index) => [ [variant.name, index], [index, variant.name], ]), ), { size }, ) as Codec; } // Data enums are decoded as discriminated unions, e.g. `{ __kind: 'Move', x: 10, y: 20 }`. const variants = node.variants.map(variant => [pascalCase(variant.name), visit(variant, this)] as const); return getDiscriminatedUnionCodec(variants, { size }) as unknown as Codec; }, visitEvent(node) { return visit(node.data, this); }, visitFixedSizeType(node) { const type = visit(node.type, this); return fixCodecSize(type, node.size); }, visitHiddenPrefixType(node) { const type = visit(node.type, this); const constants = node.prefix.map(constant => { const constantCodec = visit(constant.type, this); const constantValue = visit(constant.value, valueNodeVisitor); return getConstantCodec(constantCodec.encode(constantValue)); }); return getHiddenPrefixCodec(type, constants); }, visitHiddenSuffixType(node) { const type = visit(node.type, this); const constants = node.suffix.map(constant => { const constantCodec = visit(constant.type, this); const constantValue = visit(constant.value, valueNodeVisitor); return getConstantCodec(constantCodec.encode(constantValue)); }); return getHiddenSuffixCodec(type, constants); }, visitInstruction(node) { return visit(structTypeNodeFromInstructionArgumentNodes(node.arguments), this); }, visitInstructionArgument(node) { return visit(structFieldTypeNodeFromInstructionArgumentNode(node), this); }, visitInstructionArgumentLink(node) { const path = linkables.getPathOrThrow(stack.getPath(node.kind)); stack.pushPath(path); const result = visit(getLastNodeFromPath(path), this); stack.popPath(); return result; }, visitInstructionLink(node) { const path = linkables.getPathOrThrow(stack.getPath(node.kind)); stack.pushPath(path); const result = visit(getLastNodeFromPath(path), this); stack.popPath(); return result; }, visitMapType(node) { const key = visit(node.key, this); const value = visit(node.value, this); const size = getSizeFromCountNode(node.count, this); // Note we transform maps as objects to be compatible with JSON. return transformCodec( getMapCodec(key, value, { size }), (value: object) => new Map(Object.entries(value)), (map: Map) => Object.fromEntries(map) as object, ) as Codec; }, visitNumberType(node) { return getCodecFromNumberFormat(node.format) as Codec; }, visitOptionType(node) { const item = visit(node.item, this); const prefix = visit(node.prefix, this) as NumberCodec; if (node.fixed) { assertIsFixedSize(item); return getOptionCodec(item, { noneValue: 'zeroes', prefix }); } return getOptionCodec(item, { prefix }); }, visitPostOffsetType(node) { const type = visit(node.type, this); switch (node.strategy) { case 'padded': return padRightCodec(type, node.offset); case 'absolute': return offsetCodec(type, { postOffset: ({ wrapBytes }) => (node.offset < 0 ? wrapBytes(node.offset) : node.offset), }); case 'preOffset': return offsetCodec(type, { postOffset: ({ preOffset }) => preOffset + node.offset }); case 'relative': default: return offsetCodec(type, { postOffset: ({ postOffset }) => postOffset + node.offset }); } }, visitPreOffsetType(node) { const type = visit(node.type, this); switch (node.strategy) { case 'padded': return padLeftCodec(type, node.offset); case 'absolute': return offsetCodec(type, { preOffset: ({ wrapBytes }) => (node.offset < 0 ? wrapBytes(node.offset) : node.offset), }); case 'relative': default: return offsetCodec(type, { preOffset: ({ preOffset }) => preOffset + node.offset }); } }, visitPublicKeyType() { return fixCodecSize(getBase58Codec(), 32) as Codec; }, visitRemainderOptionType(node) { const item = visit(node.item, this); return getOptionCodec(item, { prefix: null }); }, visitSentinelType(node) { const type = visit(node.type, this); const sentinelCodec = visit(node.sentinel.type, this); const sentinelValue = visit(node.sentinel.value, valueNodeVisitor); const sentinelBytes = sentinelCodec.encode(sentinelValue); return addCodecSentinel(type, sentinelBytes); }, visitSetType(node) { const item = visit(node.item, this); const size = getSizeFromCountNode(node.count, this); // Note we use the array codecs since it is compatible with the JSON format. return getArrayCodec(item, { size }) as Codec; }, visitSizePrefixType(node) { const type = visit(node.type, this); const prefix = visit(node.prefix, this) as NumberCodec; return addCodecSizePrefix(type, prefix); }, visitSolAmountType(node) { return visit(node.number, this); }, visitStringType(node) { return getCodecFromBytesEncoding(node.encoding) as Codec; }, visitStructFieldType(node) { return visit(node.type, this); }, visitStructType(node) { const fields = node.fields.map(field => [field.name, visit(field, this)] as const); return getStructCodec(fields) as Codec; }, visitTupleType(node) { const items = node.items.map(item => visit(item, this)); return getTupleCodec(items) as Codec; }, visitZeroableOptionType(node) { const item = visit(node.item, this); assertIsFixedSize(item); if (node.zeroValue) { const noneCodec = visit(node.zeroValue.type, this); const noneValue = visit(node.zeroValue.value, valueNodeVisitor); const noneBytes = noneCodec.encode(noneValue); return getOptionCodec(item, { noneValue: noneBytes, prefix: null }); } return getOptionCodec(item, { noneValue: 'zeroes', prefix: null }); }, }; const visitor = pipe(baseVisitor, v => recordNodeStackVisitor(v, stack)); return visitor; } function getCodecFromBytesEncoding(encoding: BytesEncoding) { switch (encoding) { case 'base16': return getBase16Codec(); case 'base58': return getBase58Codec(); case 'base64': return getBase64Codec(); case 'utf8': return getUtf8Codec(); default: throw new CodamaError(CODAMA_ERROR__UNRECOGNIZED_BYTES_ENCODING, { encoding: encoding satisfies never, }); } } function getCodecFromNumberFormat(format: NumberFormat) { switch (format) { case 'u8': return getU8Codec(); case 'u16': return getU16Codec(); case 'u32': return getU32Codec(); case 'u64': return getU64Codec(); case 'u128': return getU128Codec(); case 'i8': return getI8Codec(); case 'i16': return getI16Codec(); case 'i32': return getI32Codec(); case 'i64': return getI64Codec(); case 'i128': return getI128Codec(); case 'f32': return getF32Codec(); case 'f64': return getF64Codec(); case 'shortU16': return getShortU16Codec(); default: throw new CodamaError(CODAMA_ERROR__UNRECOGNIZED_NUMBER_FORMAT, { format: format satisfies never, }); } } function getSizeFromCountNode( node: CountNode, visitor: Visitor, ): NumberCodec | number | 'remainder' { if (isNode(node, 'prefixedCountNode')) { return visit(node.prefix, visitor) as NumberCodec; } if (isNode(node, 'fixedCountNode')) { return node.value; } return 'remainder'; } ================================================ FILE: packages/dynamic-codecs/src/index.ts ================================================ import { LinkableDictionary, NodeStack } from '@codama/visitors-core'; import { containsBytes, ReadonlyUint8Array } from '@solana/codecs'; import { getNodeCodecVisitor } from './codecs'; import { getValueNodeVisitor } from './values'; export * from './codecs'; export * from './values'; export type { ReadonlyUint8Array }; export { containsBytes }; export type CodecAndValueVisitors = { codecVisitor: ReturnType; valueVisitor: ReturnType; }; export function getCodecAndValueVisitors(linkables: LinkableDictionary, options: { stack?: NodeStack } = {}) { const stack = options.stack ?? new NodeStack(); const codecVisitor = getNodeCodecVisitor(linkables, { stack }); const valueVisitor = getValueNodeVisitor(linkables, { codecVisitorFactory: () => codecVisitor, stack }); return { codecVisitor, valueVisitor }; } ================================================ FILE: packages/dynamic-codecs/src/types/global.d.ts ================================================ declare const __BROWSER__: boolean; declare const __ESM__: boolean; declare const __NODEJS__: boolean; declare const __REACTNATIVE__: boolean; declare const __TEST__: boolean; declare const __VERSION__: string; ================================================ FILE: packages/dynamic-codecs/src/values.ts ================================================ import { CODAMA_ERROR__ENUM_VARIANT_NOT_FOUND, CodamaError } from '@codama/errors'; import { assertIsNode, bytesTypeNode, isNode, isScalarEnum, pascalCase, ValueNode } from '@codama/nodes'; import { LinkableDictionary, NodeStack, pipe, recordNodeStackVisitor, visit, Visitor } from '@codama/visitors-core'; import { CodecVisitorOptions, getNodeCodecVisitor } from './codecs'; export function getValueNodeVisitor( linkables: LinkableDictionary, options: { codecVisitorFactory?: () => ReturnType; codecVisitorOptions?: CodecVisitorOptions; stack?: NodeStack; } = {}, ): Visitor { const stack = options.stack ?? new NodeStack(); let cachedCodecVisitor: ReturnType | null = null; const codecVisitorFactory = options.codecVisitorFactory ?? (() => (cachedCodecVisitor ??= getNodeCodecVisitor(linkables, { stack, ...options.codecVisitorOptions }))); const baseVisitor: Visitor = { visitArrayValue(node) { return node.items.map(item => visit(item, this)); }, visitBooleanValue(node) { return node.boolean; }, visitBytesValue(node) { return [node.encoding, node.data]; }, visitConstantValue(node) { const codec = visit(node.type, codecVisitorFactory()); const value = visit(node.value, this); const bytes = codec.encode(value); const bytesCodec = visit(bytesTypeNode(), codecVisitorFactory()); return bytesCodec.decode(bytes); }, visitEnumValue(node) { const enumType = linkables.getOrThrow([...stack.getPath(node.kind), node.enum]).type; assertIsNode(enumType, 'enumTypeNode'); const variantIndex = enumType.variants.findIndex(variant => variant.name === node.variant); if (variantIndex < 0) { throw new CodamaError(CODAMA_ERROR__ENUM_VARIANT_NOT_FOUND, { enum: node.enum, enumName: node.enum.name, variant: node.variant, }); } const variant = enumType.variants[variantIndex]; if (isScalarEnum(enumType)) return variantIndex; const kind = { __kind: pascalCase(node.variant) }; if (isNode(variant, 'enumEmptyVariantTypeNode')) return kind; if (isNode(variant, 'enumStructVariantTypeNode') && !!node.value) { const value = visit(node.value, this) as object; return { ...kind, ...value }; } if (isNode(variant, 'enumTupleVariantTypeNode') && !!node.value) { const fields = visit(node.value, this); return { ...kind, fields }; } return kind; }, visitMapValue(node) { return Object.fromEntries( node.entries.map(entry => { const key = visit(entry.key, this); const value = visit(entry.value, this); return [key, value]; }), ) as unknown; }, visitNoneValue() { return { __option: 'None' }; }, visitNumberValue(node) { return node.number; }, visitPublicKeyValue(node) { return node.publicKey; }, visitSetValue(node) { return node.items.map(item => visit(item, this)); }, visitSomeValue(node) { const value = visit(node.value, this); return { __option: 'Some', value }; }, visitStringValue(node) { return node.string; }, visitStructValue(node) { return Object.fromEntries( node.fields.map(field => { const name = field.name; const value = visit(field.value, this); return [name, value]; }), ); }, visitTupleValue(node) { return node.items.map(item => visit(item, this)); }, }; return pipe(baseVisitor, v => recordNodeStackVisitor(v, stack)); } ================================================ FILE: packages/dynamic-codecs/test/_setup.ts ================================================ import { getBase16Encoder, ReadonlyUint8Array } from '@solana/codecs'; export function hex(hexadecimal: string): ReadonlyUint8Array { return getBase16Encoder().encode(hexadecimal); } ================================================ FILE: packages/dynamic-codecs/test/codecs/AccountNode.test.ts ================================================ import { accountNode, numberTypeNode, structFieldTypeNode, structTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { getNodeCodec } from '../../src'; import { hex } from '../_setup'; test('it delegates to the underlying data node', () => { const codec = getNodeCodec([ accountNode({ data: structTypeNode([ structFieldTypeNode({ name: 'foo', type: numberTypeNode('u32'), }), ]), name: 'myAccount', }), ]); expect(codec.encode({ foo: 42 })).toStrictEqual(hex('2a000000')); expect(codec.decode(hex('2a000000'))).toStrictEqual({ foo: 42 }); }); ================================================ FILE: packages/dynamic-codecs/test/codecs/ArrayTypeNode.test.ts ================================================ import { arrayTypeNode, fixedCountNode, numberTypeNode, prefixedCountNode, remainderCountNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { getNodeCodec } from '../../src'; import { hex } from '../_setup'; test('it decodes prefixed arrays', () => { const codec = getNodeCodec([arrayTypeNode(numberTypeNode('u16'), prefixedCountNode(numberTypeNode('u32')))]); expect(codec.encode([42, 99, 650])).toStrictEqual(hex('030000002a0063008a02')); expect(codec.decode(hex('030000002a0063008a02'))).toStrictEqual([42, 99, 650]); }); test('it decodes fixed arrays', () => { const codec = getNodeCodec([arrayTypeNode(numberTypeNode('u16'), fixedCountNode(3))]); expect(codec.encode([42, 99, 650])).toStrictEqual(hex('2a0063008a02')); expect(codec.decode(hex('2a0063008a02'))).toStrictEqual([42, 99, 650]); }); test('it decodes remainder arrays', () => { const codec = getNodeCodec([arrayTypeNode(numberTypeNode('u16'), remainderCountNode())]); expect(codec.encode([42, 99, 650])).toStrictEqual(hex('2a0063008a02')); expect(codec.decode(hex('2a0063008a02'))).toStrictEqual([42, 99, 650]); }); ================================================ FILE: packages/dynamic-codecs/test/codecs/BooleanTypeNode.test.ts ================================================ import { booleanTypeNode, numberTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { getNodeCodec } from '../../src'; import { hex } from '../_setup'; test('default', () => { const codec = getNodeCodec([booleanTypeNode()]); expect(codec.encode(true)).toStrictEqual(hex('01')); expect(codec.decode(hex('01'))).toBe(true); expect(codec.encode(false)).toStrictEqual(hex('00')); expect(codec.decode(hex('00'))).toBe(false); }); test('custom number', () => { const codec = getNodeCodec([booleanTypeNode(numberTypeNode('u32'))]); expect(codec.encode(true)).toStrictEqual(hex('01000000')); expect(codec.decode(hex('01000000'))).toBe(true); expect(codec.encode(false)).toStrictEqual(hex('00000000')); expect(codec.decode(hex('00000000'))).toBe(false); }); ================================================ FILE: packages/dynamic-codecs/test/codecs/BytesTypeNode.test.ts ================================================ import { bytesTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { getNodeCodec } from '../../src'; import { hex } from '../_setup'; test('it uses base64 encoding by default', () => { const codec = getNodeCodec([bytesTypeNode()]); expect(codec.encode(['base64', 'HelloWorld++'])).toStrictEqual(hex('1de965a16a2b95dfbe')); expect(codec.decode(hex('1de965a16a2b95dfbe'))).toStrictEqual(['base64', 'HelloWorld++']); }); test('it can use a custom default encoding', () => { const codec = getNodeCodec([bytesTypeNode()], { bytesEncoding: 'base16' }); expect(codec.encode(['base16', 'deadb0d1e5'])).toStrictEqual(hex('deadb0d1e5')); expect(codec.decode(hex('deadb0d1e5'))).toStrictEqual(['base16', 'deadb0d1e5']); }); test('the first tuple item is always used when encoding the data', () => { const codec = getNodeCodec([bytesTypeNode()], { bytesEncoding: 'base64' }); expect(codec.encode(['base16', 'deadb0d1e5'])).toStrictEqual(hex('deadb0d1e5')); expect(codec.decode(hex('deadb0d1e5'))).toStrictEqual(['base64', '3q2w0eU=']); }); ================================================ FILE: packages/dynamic-codecs/test/codecs/DefinedTypeLinkNode.test.ts ================================================ import { definedTypeLinkNode, definedTypeNode, numberTypeNode, programLinkNode, programNode, rootNode, } from '@codama/nodes'; import { expect, test } from 'vitest'; import { getNodeCodec } from '../../src'; import { hex } from '../_setup'; test('it resolves the codec of defined type link nodes', () => { // Given an existing defined type and a LinkNode pointing to it. const root = rootNode( programNode({ definedTypes: [ definedTypeNode({ name: 'slot', type: numberTypeNode('u64') }), definedTypeNode({ name: 'lastSlot', type: definedTypeLinkNode('slot') }), ], name: 'myProgram', publicKey: '1111', }), ); // When we get the codec for the defined type pointing to another defined type. const codec = getNodeCodec([root, root.program, root.program.definedTypes[1]]); // Then we expect the codec to match the linked defined type. expect(codec.encode(42)).toStrictEqual(hex('2a00000000000000')); expect(codec.decode(hex('2a00000000000000'))).toBe(42n); }); test('it follows linked nodes using the correct paths', () => { // Given two link nodes designed so that the path would // fail if we did not save and restored linked paths. const programA = programNode({ definedTypes: [ definedTypeNode({ name: 'typeA', type: definedTypeLinkNode('typeB1', programLinkNode('programB')), }), ], name: 'programA', publicKey: '1111', }); const programB = programNode({ definedTypes: [ definedTypeNode({ name: 'typeB1', type: definedTypeLinkNode('typeB2') }), definedTypeNode({ name: 'typeB2', type: numberTypeNode('u64') }), ], name: 'programB', publicKey: '2222', }); const root = rootNode(programA, [programB]); // When we get the codec for the defined type in programA. const codec = getNodeCodec([root, programA, programA.definedTypes[0]]); // Then we expect the links in programB to be resolved correctly. expect(codec.encode(42)).toStrictEqual(hex('2a00000000000000')); expect(codec.decode(hex('2a00000000000000'))).toBe(42n); }); ================================================ FILE: packages/dynamic-codecs/test/codecs/DefinedTypeNode.test.ts ================================================ import { definedTypeNode, numberTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { getNodeCodec } from '../../src'; import { hex } from '../_setup'; test('it delegates to the underlying type node', () => { const codec = getNodeCodec([definedTypeNode({ name: 'foo', type: numberTypeNode('u32') })]); expect(codec.encode(42)).toStrictEqual(hex('2a000000')); expect(codec.decode(hex('2a000000'))).toBe(42); }); ================================================ FILE: packages/dynamic-codecs/test/codecs/EnumTypeNode.test.ts ================================================ import { enumEmptyVariantTypeNode, enumStructVariantTypeNode, enumTupleVariantTypeNode, enumTypeNode, fixedSizeTypeNode, numberTypeNode, stringTypeNode, structFieldTypeNode, structTypeNode, tupleTypeNode, } from '@codama/nodes'; import { expect, test } from 'vitest'; import { getNodeCodec } from '../../src'; import { hex } from '../_setup'; test('it encodes scalar enums', () => { const codec = getNodeCodec([enumTypeNode([enumEmptyVariantTypeNode('up'), enumEmptyVariantTypeNode('down')])]); expect(codec.encode(0)).toStrictEqual(hex('00')); expect(codec.decode(hex('00'))).toBe(0); expect(codec.encode(1)).toStrictEqual(hex('01')); expect(codec.decode(hex('01'))).toBe(1); }); test('it encodes scalar enums with custom sizes', () => { const codec = getNodeCodec([ enumTypeNode([enumEmptyVariantTypeNode('up'), enumEmptyVariantTypeNode('down')], { size: numberTypeNode('u16'), }), ]); expect(codec.encode(0)).toStrictEqual(hex('0000')); expect(codec.decode(hex('0000'))).toBe(0); expect(codec.encode(1)).toStrictEqual(hex('0100')); expect(codec.decode(hex('0100'))).toBe(1); }); test('it encodes data enums', () => { const codec = getNodeCodec([ enumTypeNode([ enumEmptyVariantTypeNode('quit'), enumTupleVariantTypeNode('write', tupleTypeNode([fixedSizeTypeNode(stringTypeNode('utf8'), 5)])), enumStructVariantTypeNode( 'move', structTypeNode([ structFieldTypeNode({ name: 'x', type: numberTypeNode('u8') }), structFieldTypeNode({ name: 'y', type: numberTypeNode('u8') }), ]), ), ]), ]); const quitVariant = { __kind: 'Quit' }; expect(codec.encode(quitVariant)).toStrictEqual(hex('00')); expect(codec.decode(hex('00'))).toStrictEqual(quitVariant); const writeVariant = { __kind: 'Write', fields: ['Hello'] }; expect(codec.encode(writeVariant)).toStrictEqual(hex('0148656c6c6f')); expect(codec.decode(hex('0148656c6c6f'))).toStrictEqual(writeVariant); const moveVariant = { __kind: 'Move', x: 10, y: 20 }; expect(codec.encode(moveVariant)).toStrictEqual(hex('020a14')); expect(codec.decode(hex('020a14'))).toStrictEqual(moveVariant); }); test('it encodes data enums with custom sizes', () => { const codec = getNodeCodec([ enumTypeNode( [ enumEmptyVariantTypeNode('quit'), enumTupleVariantTypeNode('write', tupleTypeNode([fixedSizeTypeNode(stringTypeNode('utf8'), 5)])), ], { size: numberTypeNode('u16') }, ), ]); const quitVariant = { __kind: 'Quit' }; expect(codec.encode(quitVariant)).toStrictEqual(hex('0000')); expect(codec.decode(hex('0000'))).toStrictEqual(quitVariant); const writeVariant = { __kind: 'Write', fields: ['Hello'] }; expect(codec.encode(writeVariant)).toStrictEqual(hex('010048656c6c6f')); expect(codec.decode(hex('010048656c6c6f'))).toStrictEqual(writeVariant); }); ================================================ FILE: packages/dynamic-codecs/test/codecs/EventNode.test.ts ================================================ import { eventNode, numberTypeNode, structFieldTypeNode, structTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { getNodeCodec } from '../../src'; import { hex } from '../_setup'; test('it delegates to the underlying event data node', () => { const codec = getNodeCodec([ eventNode({ data: structTypeNode([ structFieldTypeNode({ name: 'foo', type: numberTypeNode('u32'), }), ]), name: 'myEvent', }), ]); expect(codec.encode({ foo: 42 })).toStrictEqual(hex('2a000000')); expect(codec.decode(hex('2a000000'))).toStrictEqual({ foo: 42 }); }); ================================================ FILE: packages/dynamic-codecs/test/codecs/FixedSizeTypeNode.test.ts ================================================ import { fixedSizeTypeNode, stringTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { getNodeCodec } from '../../src'; import { hex } from '../_setup'; test('it decodes fixed size strings', () => { const codec = getNodeCodec([fixedSizeTypeNode(stringTypeNode('utf8'), 5)]); expect(codec.encode('Hello')).toStrictEqual(hex('48656c6c6f')); expect(codec.decode(hex('48656c6c6f'))).toBe('Hello'); expect(codec.encode('Sup')).toStrictEqual(hex('5375700000')); expect(codec.decode(hex('5375700000'))).toBe('Sup'); }); ================================================ FILE: packages/dynamic-codecs/test/codecs/HiddenPrefixTypeNode.test.ts ================================================ import { constantValueNode, fixedSizeTypeNode, hiddenPrefixTypeNode, numberTypeNode, numberValueNode, stringTypeNode, } from '@codama/nodes'; import { expect, test } from 'vitest'; import { getNodeCodec } from '../../src'; import { hex } from '../_setup'; test('it hides hidden prefixes from the main type', () => { const codec = getNodeCodec([ hiddenPrefixTypeNode(fixedSizeTypeNode(stringTypeNode('utf8'), 5), [ constantValueNode(numberTypeNode('u64'), numberValueNode(42)), ]), ]); expect(codec.encode('Alice')).toStrictEqual(hex('2a00000000000000416c696365')); expect(codec.decode(hex('2a00000000000000416c696365'))).toStrictEqual('Alice'); }); ================================================ FILE: packages/dynamic-codecs/test/codecs/HiddenSuffixTypeNode.test.ts ================================================ import { constantValueNode, fixedSizeTypeNode, hiddenSuffixTypeNode, numberTypeNode, numberValueNode, stringTypeNode, } from '@codama/nodes'; import { expect, test } from 'vitest'; import { getNodeCodec } from '../../src'; import { hex } from '../_setup'; test('it hides hidden suffixes from the main type', () => { const codec = getNodeCodec([ hiddenSuffixTypeNode(fixedSizeTypeNode(stringTypeNode('utf8'), 5), [ constantValueNode(numberTypeNode('u64'), numberValueNode(42)), ]), ]); expect(codec.encode('Alice')).toStrictEqual(hex('416c6963652a00000000000000')); expect(codec.decode(hex('416c6963652a00000000000000'))).toStrictEqual('Alice'); }); ================================================ FILE: packages/dynamic-codecs/test/codecs/InstructionArgumentNode.test.ts ================================================ import { instructionArgumentNode, numberTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { getNodeCodec } from '../../src'; import { hex } from '../_setup'; test('it delegates to the type node of the argument', () => { const codec = getNodeCodec([ instructionArgumentNode({ name: 'foo', type: numberTypeNode('u32'), }), ]); expect(codec.encode(42)).toStrictEqual(hex('2a000000')); expect(codec.decode(hex('2a000000'))).toStrictEqual(42); }); ================================================ FILE: packages/dynamic-codecs/test/codecs/InstructionNode.test.ts ================================================ import { instructionArgumentNode, instructionNode, numberTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { getNodeCodec } from '../../src'; import { hex } from '../_setup'; test('it delegates to the instruction arguments as a struct', () => { const codec = getNodeCodec([ instructionNode({ arguments: [ instructionArgumentNode({ name: 'foo', type: numberTypeNode('u32'), }), ], name: 'myInstruction', }), ]); expect(codec.encode({ foo: 42 })).toStrictEqual(hex('2a000000')); expect(codec.decode(hex('2a000000'))).toStrictEqual({ foo: 42 }); }); ================================================ FILE: packages/dynamic-codecs/test/codecs/MapTypeNode.test.ts ================================================ import { fixedCountNode, fixedSizeTypeNode, mapTypeNode, numberTypeNode, prefixedCountNode, remainderCountNode, stringTypeNode, } from '@codama/nodes'; import { expect, test } from 'vitest'; import { getNodeCodec } from '../../src'; import { hex } from '../_setup'; test('it decodes prefixed maps as objects', () => { const key = fixedSizeTypeNode(stringTypeNode('utf8'), 3); const value = numberTypeNode('u16'); const codec = getNodeCodec([mapTypeNode(key, value, prefixedCountNode(numberTypeNode('u32')))]); // eslint-disable-next-line sort-keys-fix/sort-keys-fix const map = { foo: 42, bar: 99, baz: 650 }; expect(codec.encode(map)).toStrictEqual(hex('03000000666f6f2a00626172630062617a8a02')); expect(codec.decode(hex('03000000666f6f2a00626172630062617a8a02'))).toStrictEqual(map); }); test('it decodes fixed maps as objects', () => { const key = fixedSizeTypeNode(stringTypeNode('utf8'), 3); const value = numberTypeNode('u16'); const codec = getNodeCodec([mapTypeNode(key, value, fixedCountNode(3))]); // eslint-disable-next-line sort-keys-fix/sort-keys-fix const map = { foo: 42, bar: 99, baz: 650 }; expect(codec.encode(map)).toStrictEqual(hex('666f6f2a00626172630062617a8a02')); expect(codec.decode(hex('666f6f2a00626172630062617a8a02'))).toStrictEqual(map); }); test('it decodes remainder maps as objects', () => { const key = fixedSizeTypeNode(stringTypeNode('utf8'), 3); const value = numberTypeNode('u16'); const codec = getNodeCodec([mapTypeNode(key, value, remainderCountNode())]); // eslint-disable-next-line sort-keys-fix/sort-keys-fix const map = { foo: 42, bar: 99, baz: 650 }; expect(codec.encode(map)).toStrictEqual(hex('666f6f2a00626172630062617a8a02')); expect(codec.decode(hex('666f6f2a00626172630062617a8a02'))).toStrictEqual(map); }); ================================================ FILE: packages/dynamic-codecs/test/codecs/NumberTypeNode.test.ts ================================================ import { numberTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { getNodeCodec } from '../../src'; import { hex } from '../_setup'; test('u8', () => { const codec = getNodeCodec([numberTypeNode('u8')]); expect(codec.encode(42)).toStrictEqual(hex('2a')); expect(codec.decode(hex('2a'))).toBe(42); }); test('u16', () => { const codec = getNodeCodec([numberTypeNode('u16')]); expect(codec.encode(42)).toStrictEqual(hex('2a00')); expect(codec.decode(hex('2a00'))).toBe(42); }); test('u32', () => { const codec = getNodeCodec([numberTypeNode('u32')]); expect(codec.encode(42)).toStrictEqual(hex('2a000000')); expect(codec.decode(hex('2a000000'))).toBe(42); }); test('u64', () => { const codec = getNodeCodec([numberTypeNode('u64')]); expect(codec.encode(42)).toStrictEqual(hex('2a00000000000000')); expect(codec.decode(hex('2a00000000000000'))).toBe(42n); }); test('u128', () => { const codec = getNodeCodec([numberTypeNode('u128')]); expect(codec.encode(42)).toStrictEqual(hex('2a000000000000000000000000000000')); expect(codec.decode(hex('2a000000000000000000000000000000'))).toBe(42n); }); test('i8', () => { const codec = getNodeCodec([numberTypeNode('i8')]); expect(codec.encode(-42)).toStrictEqual(hex('d6')); expect(codec.decode(hex('d6'))).toBe(-42); }); test('i16', () => { const codec = getNodeCodec([numberTypeNode('i16')]); expect(codec.encode(-42)).toStrictEqual(hex('d6ff')); expect(codec.decode(hex('d6ff'))).toBe(-42); }); test('i32', () => { const codec = getNodeCodec([numberTypeNode('i32')]); expect(codec.encode(-42)).toStrictEqual(hex('d6ffffff')); expect(codec.decode(hex('d6ffffff'))).toBe(-42); }); test('i64', () => { const codec = getNodeCodec([numberTypeNode('i64')]); expect(codec.encode(-42)).toStrictEqual(hex('d6ffffffffffffff')); expect(codec.decode(hex('d6ffffffffffffff'))).toBe(-42n); }); test('i128', () => { const codec = getNodeCodec([numberTypeNode('i128')]); expect(codec.encode(-42)).toStrictEqual(hex('d6ffffffffffffffffffffffffffffff')); expect(codec.decode(hex('d6ffffffffffffffffffffffffffffff'))).toBe(-42n); }); test('f32', () => { const codec = getNodeCodec([numberTypeNode('f32')]); expect(codec.encode(1.5)).toStrictEqual(hex('0000c03f')); expect(codec.decode(hex('0000c03f'))).toBe(1.5); }); test('f64', () => { const codec = getNodeCodec([numberTypeNode('f64')]); expect(codec.encode(1.5)).toStrictEqual(hex('000000000000f83f')); expect(codec.decode(hex('000000000000f83f'))).toBe(1.5); }); test('shortU16', () => { const codec = getNodeCodec([numberTypeNode('shortU16')]); expect(codec.encode(42)).toStrictEqual(hex('2a')); expect(codec.decode(hex('2a'))).toBe(42); expect(codec.encode(128)).toStrictEqual(hex('8001')); expect(codec.decode(hex('8001'))).toBe(128); }); ================================================ FILE: packages/dynamic-codecs/test/codecs/OptionTypeNode.test.ts ================================================ import { numberTypeNode, optionTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { getNodeCodec } from '../../src'; import { hex } from '../_setup'; test('it encodes prefixed options', () => { const codec = getNodeCodec([optionTypeNode(numberTypeNode('u16'))]); expect(codec.encode({ __option: 'Some', value: 42 })).toStrictEqual(hex('012a00')); expect(codec.decode(hex('012a00'))).toStrictEqual({ __option: 'Some', value: 42 }); expect(codec.encode({ __option: 'None' })).toStrictEqual(hex('00')); expect(codec.decode(hex('00'))).toStrictEqual({ __option: 'None' }); }); test('it encodes prefixed options with custom sizes', () => { const codec = getNodeCodec([optionTypeNode(numberTypeNode('u16'), { prefix: numberTypeNode('u32') })]); expect(codec.encode({ __option: 'Some', value: 42 })).toStrictEqual(hex('010000002a00')); expect(codec.decode(hex('010000002a00'))).toStrictEqual({ __option: 'Some', value: 42 }); expect(codec.encode({ __option: 'None' })).toStrictEqual(hex('00000000')); expect(codec.decode(hex('00000000'))).toStrictEqual({ __option: 'None' }); }); test('it encodes prefixed options with fixed size items', () => { const codec = getNodeCodec([optionTypeNode(numberTypeNode('u16'), { fixed: true })]); expect(codec.encode({ __option: 'Some', value: 42 })).toStrictEqual(hex('012a00')); expect(codec.decode(hex('012a00'))).toStrictEqual({ __option: 'Some', value: 42 }); expect(codec.encode({ __option: 'None' })).toStrictEqual(hex('000000')); expect(codec.decode(hex('000000'))).toStrictEqual({ __option: 'None' }); }); ================================================ FILE: packages/dynamic-codecs/test/codecs/PostOffsetTypeNode.test.ts ================================================ import { fixedSizeTypeNode, numberTypeNode, postOffsetTypeNode, preOffsetTypeNode, tupleTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { getNodeCodec } from '../../src'; import { hex } from '../_setup'; test('it encodes relative post-offsets', () => { const node = tupleTypeNode([ postOffsetTypeNode(fixedSizeTypeNode(numberTypeNode('u8'), 4), -2), numberTypeNode('u8'), ]); const codec = getNodeCodec([node]); expect(codec.encode([0xaa, 0xff])).toStrictEqual(hex('aa00ff0000')); expect(codec.decode(hex('aa00ff0000'))).toStrictEqual([0xaa, 0xff]); }); test('it encodes padded post-offsets', () => { const node = tupleTypeNode([postOffsetTypeNode(numberTypeNode('u8'), 4, 'padded'), numberTypeNode('u8')]); const codec = getNodeCodec([node]); expect(codec.encode([0xaa, 0xff])).toStrictEqual(hex('aa00000000ff')); expect(codec.decode(hex('aa00000000ff'))).toStrictEqual([0xaa, 0xff]); }); test('it encodes absolute post-offsets', () => { const node = tupleTypeNode([ postOffsetTypeNode(fixedSizeTypeNode(numberTypeNode('u8'), 4), -2, 'absolute'), numberTypeNode('u8'), ]); const codec = getNodeCodec([node]); expect(codec.encode([0xaa, 0xff])).toStrictEqual(hex('aa0000ff00')); expect(codec.decode(hex('aa0000ff00'))).toStrictEqual([0xaa, 0xff]); }); test('it encodes post-offsets relative to the previous pre-offset', () => { const node = tupleTypeNode([ postOffsetTypeNode(preOffsetTypeNode(numberTypeNode('u8'), 4, 'padded'), 0, 'preOffset'), numberTypeNode('u8'), ]); const codec = getNodeCodec([node]); expect(codec.encode([0xaa, 0xff])).toStrictEqual(hex('ff000000aa00')); expect(codec.decode(hex('ff000000aa00'))).toStrictEqual([0xaa, 0xff]); }); ================================================ FILE: packages/dynamic-codecs/test/codecs/PreOffsetTypeNode.test.ts ================================================ import { numberTypeNode, preOffsetTypeNode, tupleTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { getNodeCodec } from '../../src'; import { hex } from '../_setup'; test('it encodes relative pre-offsets', () => { const node = tupleTypeNode([ preOffsetTypeNode(numberTypeNode('u8'), 1), preOffsetTypeNode(numberTypeNode('u8'), -2), ]); const codec = getNodeCodec([node]); expect(codec.encode([0xaa, 0xff])).toStrictEqual(hex('ffaa')); expect(codec.decode(hex('ffaa'))).toStrictEqual([0xaa, 0xff]); }); test('it encodes padded pre-offsets', () => { const node = tupleTypeNode([preOffsetTypeNode(numberTypeNode('u8'), 4, 'padded'), numberTypeNode('u8')]); const codec = getNodeCodec([node]); expect(codec.encode([0xaa, 0xff])).toStrictEqual(hex('00000000aaff')); expect(codec.decode(hex('00000000aaff'))).toStrictEqual([0xaa, 0xff]); }); test('it encodes absolute pre-offsets', () => { const node = tupleTypeNode([ preOffsetTypeNode(numberTypeNode('u8'), 1), preOffsetTypeNode(numberTypeNode('u8'), 0, 'absolute'), ]); const codec = getNodeCodec([node]); expect(codec.encode([0xaa, 0xff])).toStrictEqual(hex('ffaa')); expect(codec.decode(hex('ffaa'))).toStrictEqual([0xaa, 0xff]); }); ================================================ FILE: packages/dynamic-codecs/test/codecs/PublicKeyTypeNode.test.ts ================================================ import { publicKeyTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { getNodeCodec } from '../../src'; import { hex } from '../_setup'; test('it decodes as a base58 string', () => { const codec = getNodeCodec([publicKeyTypeNode()]); expect(codec.encode('LorisCg1FTs89a32VSrFskYDgiRbNQzct1WxyZb7nuA')).toStrictEqual( hex('0513045e052f4919b608963de73c666e0672e06e28140ab841bff1cc83a178b5'), ); expect(codec.decode(hex('0513045e052f4919b608963de73c666e0672e06e28140ab841bff1cc83a178b5'))).toBe( 'LorisCg1FTs89a32VSrFskYDgiRbNQzct1WxyZb7nuA', ); }); ================================================ FILE: packages/dynamic-codecs/test/codecs/RemainderOptionTypeNode.test.ts ================================================ import { numberTypeNode, remainderOptionTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { getNodeCodec } from '../../src'; import { hex } from '../_setup'; test('it encodes remainder options', () => { const codec = getNodeCodec([remainderOptionTypeNode(numberTypeNode('u16'))]); expect(codec.encode({ __option: 'Some', value: 42 })).toStrictEqual(hex('2a00')); expect(codec.decode(hex('2a00'))).toStrictEqual({ __option: 'Some', value: 42 }); expect(codec.encode({ __option: 'None' })).toStrictEqual(hex('')); expect(codec.decode(hex(''))).toStrictEqual({ __option: 'None' }); }); ================================================ FILE: packages/dynamic-codecs/test/codecs/SentinelTypeNode.test.ts ================================================ import { constantValueNodeFromBytes, sentinelTypeNode, stringTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { getNodeCodec } from '../../src'; import { hex } from '../_setup'; test('it encodes sentinel types', () => { const sentinel = constantValueNodeFromBytes('base16', 'ffff'); const codec = getNodeCodec([sentinelTypeNode(stringTypeNode('utf8'), sentinel)]); expect(codec.encode('Hello World!')).toStrictEqual(hex('48656c6c6f20576f726c6421ffff')); expect(codec.decode(hex('48656c6c6f20576f726c6421ffff'))).toBe('Hello World!'); }); ================================================ FILE: packages/dynamic-codecs/test/codecs/SetTypeNode.test.ts ================================================ import { fixedCountNode, numberTypeNode, prefixedCountNode, remainderCountNode, setTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { getNodeCodec } from '../../src'; import { hex } from '../_setup'; test('it decodes prefixed sets', () => { const codec = getNodeCodec([setTypeNode(numberTypeNode('u16'), prefixedCountNode(numberTypeNode('u32')))]); expect(codec.encode([42, 99, 650])).toStrictEqual(hex('030000002a0063008a02')); expect(codec.decode(hex('030000002a0063008a02'))).toStrictEqual([42, 99, 650]); }); test('it decodes fixed sets', () => { const codec = getNodeCodec([setTypeNode(numberTypeNode('u16'), fixedCountNode(3))]); expect(codec.encode([42, 99, 650])).toStrictEqual(hex('2a0063008a02')); expect(codec.decode(hex('2a0063008a02'))).toStrictEqual([42, 99, 650]); }); test('it decodes remainder sets', () => { const codec = getNodeCodec([setTypeNode(numberTypeNode('u16'), remainderCountNode())]); expect(codec.encode([42, 99, 650])).toStrictEqual(hex('2a0063008a02')); expect(codec.decode(hex('2a0063008a02'))).toStrictEqual([42, 99, 650]); }); ================================================ FILE: packages/dynamic-codecs/test/codecs/SizePrefixTypeNode.test.ts ================================================ import { numberTypeNode, sizePrefixTypeNode, stringTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { getNodeCodec } from '../../src'; import { hex } from '../_setup'; test('it encodes types prefixed with their sizes', () => { const codec = getNodeCodec([sizePrefixTypeNode(stringTypeNode('utf8'), numberTypeNode('u32'))]); expect(codec.encode('Hello World!')).toStrictEqual(hex('0c00000048656c6c6f20576f726c6421')); expect(codec.decode(hex('0c00000048656c6c6f20576f726c6421'))).toBe('Hello World!'); }); ================================================ FILE: packages/dynamic-codecs/test/codecs/StringTypeNode.test.ts ================================================ import { stringTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { getNodeCodec } from '../../src'; import { hex } from '../_setup'; test('base16', () => { const codec = getNodeCodec([stringTypeNode('base16')]); expect(codec.encode('deadb0d1e5')).toStrictEqual(hex('deadb0d1e5')); expect(codec.decode(hex('deadb0d1e5'))).toBe('deadb0d1e5'); }); test('base58', () => { const codec = getNodeCodec([stringTypeNode('base58')]); expect(codec.encode('heLLo')).toStrictEqual(hex('1b6a3070')); expect(codec.decode(hex('1b6a3070'))).toBe('heLLo'); }); test('base64', () => { const codec = getNodeCodec([stringTypeNode('base64')]); expect(codec.encode('HelloWorld++')).toStrictEqual(hex('1de965a16a2b95dfbe')); expect(codec.decode(hex('1de965a16a2b95dfbe'))).toBe('HelloWorld++'); }); test('utf8', () => { const codec = getNodeCodec([stringTypeNode('utf8')]); expect(codec.encode('Hello World!')).toStrictEqual(hex('48656c6c6f20576f726c6421')); expect(codec.decode(hex('48656c6c6f20576f726c6421'))).toBe('Hello World!'); }); ================================================ FILE: packages/dynamic-codecs/test/codecs/StructFieldTypeNode.test.ts ================================================ import { numberTypeNode, structFieldTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { getNodeCodec } from '../../src'; import { hex } from '../_setup'; test('it encodes struct fields using their types', () => { const codec = getNodeCodec([structFieldTypeNode({ name: 'age', type: numberTypeNode('u16') })]); expect(codec.encode(42)).toStrictEqual(hex('2a00')); expect(codec.decode(hex('2a00'))).toStrictEqual(42); }); ================================================ FILE: packages/dynamic-codecs/test/codecs/StructTypeNode.test.ts ================================================ import { fixedSizeTypeNode, numberTypeNode, stringTypeNode, structFieldTypeNode, structTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { getNodeCodec } from '../../src'; import { hex } from '../_setup'; test('it encodes structs', () => { const codec = getNodeCodec([ structTypeNode([ structFieldTypeNode({ name: 'firstname', type: fixedSizeTypeNode(stringTypeNode('utf8'), 5) }), structFieldTypeNode({ name: 'age', type: numberTypeNode('u16') }), ]), ]); const person = { age: 42, firstname: 'Alice' }; expect(codec.encode(person)).toStrictEqual(hex('416c6963652a00')); expect(codec.decode(hex('416c6963652a00'))).toStrictEqual(person); }); ================================================ FILE: packages/dynamic-codecs/test/codecs/TupleTypeNode.test.ts ================================================ import { fixedSizeTypeNode, numberTypeNode, stringTypeNode, tupleTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { getNodeCodec } from '../../src'; import { hex } from '../_setup'; test('it encodes tuples', () => { const codec = getNodeCodec([tupleTypeNode([fixedSizeTypeNode(stringTypeNode('utf8'), 3), numberTypeNode('u16')])]); expect(codec.encode(['foo', 42])).toStrictEqual(hex('666f6f2a00')); expect(codec.decode(hex('666f6f2a00'))).toStrictEqual(['foo', 42]); }); ================================================ FILE: packages/dynamic-codecs/test/codecs/ZeroableOptionTypeNode.test.ts ================================================ import { constantValueNodeFromBytes, numberTypeNode, zeroableOptionTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { getNodeCodec } from '../../src'; import { hex } from '../_setup'; test('it encodes zeroable options', () => { const codec = getNodeCodec([zeroableOptionTypeNode(numberTypeNode('u16'))]); expect(codec.encode({ __option: 'Some', value: 42 })).toStrictEqual(hex('2a00')); expect(codec.decode(hex('2a00'))).toStrictEqual({ __option: 'Some', value: 42 }); expect(codec.encode({ __option: 'None' })).toStrictEqual(hex('0000')); expect(codec.decode(hex('0000'))).toStrictEqual({ __option: 'None' }); }); test('it encodes zeroable options with custom zero values', () => { const zeroValue = constantValueNodeFromBytes('base16', 'ffff'); const codec = getNodeCodec([zeroableOptionTypeNode(numberTypeNode('u16'), zeroValue)]); expect(codec.encode({ __option: 'Some', value: 42 })).toStrictEqual(hex('2a00')); expect(codec.decode(hex('2a00'))).toStrictEqual({ __option: 'Some', value: 42 }); expect(codec.encode({ __option: 'None' })).toStrictEqual(hex('ffff')); expect(codec.decode(hex('ffff'))).toStrictEqual({ __option: 'None' }); }); ================================================ FILE: packages/dynamic-codecs/test/types/global.d.ts ================================================ declare const __BROWSER__: boolean; declare const __ESM__: boolean; declare const __NODEJS__: boolean; declare const __REACTNATIVE__: boolean; declare const __TEST__: boolean; declare const __VERSION__: string; ================================================ FILE: packages/dynamic-codecs/test/values/ArrayValueNode.test.ts ================================================ import { arrayValueNode, numberValueNode } from '@codama/nodes'; import { LinkableDictionary, visit } from '@codama/visitors-core'; import { expect, test } from 'vitest'; import { getValueNodeVisitor } from '../../src'; test('it returns an array of all resolved value nodes', () => { const node = arrayValueNode([numberValueNode(1), numberValueNode(2), numberValueNode(3)]); const result = visit(node, getValueNodeVisitor(new LinkableDictionary())); expect(result).toStrictEqual([1, 2, 3]); }); ================================================ FILE: packages/dynamic-codecs/test/values/BytesValueNode.test.ts ================================================ import { bytesValueNode } from '@codama/nodes'; import { LinkableDictionary, visit } from '@codama/visitors-core'; import { expect, test } from 'vitest'; import { getValueNodeVisitor } from '../../src'; test('it returns a tuple with encoding and encoded data', () => { const node = bytesValueNode('base58', 'heLLo'); const result = visit(node, getValueNodeVisitor(new LinkableDictionary())); expect(result).toStrictEqual(['base58', 'heLLo']); }); ================================================ FILE: packages/dynamic-codecs/test/values/ConstantValueNode.test.ts ================================================ import { booleanTypeNode, booleanValueNode, bytesTypeNode, bytesValueNode, constantValueNode, fixedSizeTypeNode, noneValueNode, numberTypeNode, numberValueNode, optionTypeNode, someValueNode, stringTypeNode, stringValueNode, structFieldTypeNode, structFieldValueNode, structTypeNode, structValueNode, } from '@codama/nodes'; import { LinkableDictionary, visit } from '@codama/visitors-core'; import { expect, test } from 'vitest'; import { getNodeCodecVisitor, getValueNodeVisitor } from '../../src'; test('it returns bytes from encoded numbers', () => { const node = constantValueNode(numberTypeNode('u32'), numberValueNode(42)); const result = visit(node, getValueNodeVisitor(new LinkableDictionary())); expect(result).toStrictEqual(['base64', 'KgAAAA==']); }); test('it uses the default byte encoding from the codec visitor', () => { const node = constantValueNode(numberTypeNode('u32'), numberValueNode(42)); const linkables = new LinkableDictionary(); const codecVisitorFactory = () => getNodeCodecVisitor(linkables, { bytesEncoding: 'base16' }); const result = visit(node, getValueNodeVisitor(linkables, { codecVisitorFactory })); expect(result).toStrictEqual(['base16', '2a000000']); }); test('it uses the default byte encoding from the codec visitor options', () => { const node = constantValueNode(numberTypeNode('u32'), numberValueNode(42)); const result = visit( node, getValueNodeVisitor(new LinkableDictionary(), { codecVisitorOptions: { bytesEncoding: 'base16' } }), ); expect(result).toStrictEqual(['base16', '2a000000']); }); test('it returns bytes from byte values', () => { const node = constantValueNode(bytesTypeNode(), bytesValueNode('base16', 'deadb0d1e5')); const result = visit(node, getValueNodeVisitor(new LinkableDictionary())); expect(result).toStrictEqual(['base64', '3q2w0eU=']); }); test('it returns bytes from string values', () => { const node = constantValueNode(stringTypeNode('base16'), stringValueNode('deadb0d1e5')); const result = visit(node, getValueNodeVisitor(new LinkableDictionary())); expect(result).toStrictEqual(['base64', '3q2w0eU=']); }); test('it returns bytes from boolean values', () => { const visitor = getValueNodeVisitor(new LinkableDictionary(), { codecVisitorOptions: { bytesEncoding: 'base16' } }); const resultFalse = visit(constantValueNode(booleanTypeNode(), booleanValueNode(false)), visitor); const resultTrue = visit(constantValueNode(booleanTypeNode(), booleanValueNode(true)), visitor); expect(resultFalse).toStrictEqual(['base16', '00']); expect(resultTrue).toStrictEqual(['base16', '01']); }); test('it returns bytes from struct values', () => { const node = constantValueNode( structTypeNode([ structFieldTypeNode({ name: 'firstname', type: fixedSizeTypeNode(stringTypeNode('utf8'), 5) }), structFieldTypeNode({ name: 'age', type: numberTypeNode('u16') }), ]), structValueNode([ structFieldValueNode('firstname', stringValueNode('John')), structFieldValueNode('age', stringValueNode('42')), ]), ); const visitor = getValueNodeVisitor(new LinkableDictionary(), { codecVisitorOptions: { bytesEncoding: 'base16' } }); const result = visit(node, visitor); expect(result).toStrictEqual(['base16', '4a6f686e002a00']); }); test('it returns bytes from option values', () => { const visitor = getValueNodeVisitor(new LinkableDictionary(), { codecVisitorOptions: { bytesEncoding: 'base16' } }); const type = optionTypeNode(numberTypeNode('u16')); const resultNone = visit(constantValueNode(type, noneValueNode()), visitor); const resultSome = visit(constantValueNode(type, someValueNode(numberValueNode(42))), visitor); expect(resultNone).toStrictEqual(['base16', '00']); expect(resultSome).toStrictEqual(['base16', '012a00']); }); ================================================ FILE: packages/dynamic-codecs/test/values/EnumValueNode.test.ts ================================================ import { definedTypeNode, enumEmptyVariantTypeNode, enumStructVariantTypeNode, enumTupleVariantTypeNode, enumTypeNode, enumValueNode, fixedSizeTypeNode, numberTypeNode, numberValueNode, programNode, rootNode, stringTypeNode, stringValueNode, structFieldTypeNode, structFieldValueNode, structTypeNode, structValueNode, tupleTypeNode, tupleValueNode, } from '@codama/nodes'; import { LinkableDictionary, NodeStack, visit } from '@codama/visitors-core'; import { expect, test } from 'vitest'; import { getValueNodeVisitor } from '../../src'; test('it returns scalar enum values as numbers', () => { // Given a program with a scalar enum. const definedType = definedTypeNode({ name: 'direction', type: enumTypeNode([ enumEmptyVariantTypeNode('up'), enumEmptyVariantTypeNode('right'), enumEmptyVariantTypeNode('down'), enumEmptyVariantTypeNode('left'), ]), }); const root = rootNode(programNode({ definedTypes: [definedType], name: 'myProgram', publicKey: '1111' })); // And a LinkableDictionary that recorded the enum. const linkables = new LinkableDictionary(); linkables.recordPath([root, root.program, definedType]); // And a value node visitor that's under the same program. const stack = new NodeStack([root, root.program]); const visitor = getValueNodeVisitor(linkables, { stack }); // When we visit enum value nodes for this enum type. const resultUp = visit(enumValueNode('direction', 'up'), visitor); const resultRight = visit(enumValueNode('direction', 'right'), visitor); const resultDown = visit(enumValueNode('direction', 'down'), visitor); const resultLeft = visit(enumValueNode('direction', 'left'), visitor); // Then we expect the values to be resolved from the linkable type as numbers. expect(resultUp).toBe(0); expect(resultRight).toBe(1); expect(resultDown).toBe(2); expect(resultLeft).toBe(3); }); test('it returns data enum values as objects', () => { // Given a program with a data enum. const definedType = definedTypeNode({ name: 'action', type: enumTypeNode([ enumEmptyVariantTypeNode('quit'), enumTupleVariantTypeNode('write', tupleTypeNode([fixedSizeTypeNode(stringTypeNode('utf8'), 5)])), enumStructVariantTypeNode( 'move', structTypeNode([ structFieldTypeNode({ name: 'x', type: numberTypeNode('u8') }), structFieldTypeNode({ name: 'y', type: numberTypeNode('u8') }), ]), ), ]), }); const root = rootNode(programNode({ definedTypes: [definedType], name: 'myProgram', publicKey: '1111' })); // And a LinkableDictionary that recorded the enum. const linkables = new LinkableDictionary(); linkables.recordPath([root, root.program, definedType]); // And a value node visitor that's under the same program. const stack = new NodeStack([root, root.program]); const visitor = getValueNodeVisitor(linkables, { stack }); // When we visit enum value nodes for this enum type. const resultQuit = visit(enumValueNode('action', 'quit'), visitor); const resultWrite = visit(enumValueNode('action', 'write', tupleValueNode([stringValueNode('Hello')])), visitor); const resultMove = visit( enumValueNode( 'action', 'move', structValueNode([ structFieldValueNode('x', numberValueNode(10)), structFieldValueNode('y', numberValueNode(20)), ]), ), visitor, ); // Then we expect the values to be resolved from the linkable type as numbers. expect(resultQuit).toStrictEqual({ __kind: 'Quit' }); expect(resultWrite).toStrictEqual({ __kind: 'Write', fields: ['Hello'] }); expect(resultMove).toStrictEqual({ __kind: 'Move', x: 10, y: 20 }); }); ================================================ FILE: packages/dynamic-codecs/test/values/MapValueNode.test.ts ================================================ import { mapEntryValueNode, mapValueNode, numberValueNode, stringValueNode } from '@codama/nodes'; import { LinkableDictionary, visit } from '@codama/visitors-core'; import { expect, test } from 'vitest'; import { getValueNodeVisitor } from '../../src'; test('it resolves map value nodes as objects', () => { const node = mapValueNode([ mapEntryValueNode(stringValueNode('foo'), numberValueNode(1)), mapEntryValueNode(stringValueNode('bar'), numberValueNode(2)), mapEntryValueNode(stringValueNode('baz'), numberValueNode(3)), ]); const result = visit(node, getValueNodeVisitor(new LinkableDictionary())); expect(result).toStrictEqual({ bar: 2, baz: 3, foo: 1 }); }); ================================================ FILE: packages/dynamic-codecs/test/values/NoneValueNode.test.ts ================================================ import { noneValueNode } from '@codama/nodes'; import { LinkableDictionary, visit } from '@codama/visitors-core'; import { expect, test } from 'vitest'; import { getValueNodeVisitor } from '../../src'; test('it returns a None value object', () => { const result = visit(noneValueNode(), getValueNodeVisitor(new LinkableDictionary())); expect(result).toStrictEqual({ __option: 'None' }); }); ================================================ FILE: packages/dynamic-codecs/test/values/NumberValueNode.test.ts ================================================ import { numberValueNode } from '@codama/nodes'; import { LinkableDictionary, visit } from '@codama/visitors-core'; import { expect, test } from 'vitest'; import { getValueNodeVisitor } from '../../src'; test('it returns the number as-is', () => { const result = visit(numberValueNode(42), getValueNodeVisitor(new LinkableDictionary())); expect(result).toBe(42); }); ================================================ FILE: packages/dynamic-codecs/test/values/PublicKeyValueNode.test.ts ================================================ import { publicKeyValueNode } from '@codama/nodes'; import { LinkableDictionary, visit } from '@codama/visitors-core'; import { expect, test } from 'vitest'; import { getValueNodeVisitor } from '../../src'; test('it returns the public key as-is', () => { const visitor = getValueNodeVisitor(new LinkableDictionary()); const result = visit(publicKeyValueNode('B3SqCE8ww4xmoPcfm1gGibZENPkPCVp3jNwkYcg7xS6j'), visitor); expect(result).toBe('B3SqCE8ww4xmoPcfm1gGibZENPkPCVp3jNwkYcg7xS6j'); }); ================================================ FILE: packages/dynamic-codecs/test/values/SetValueNode.test.ts ================================================ import { numberValueNode, setValueNode } from '@codama/nodes'; import { LinkableDictionary, visit } from '@codama/visitors-core'; import { expect, test } from 'vitest'; import { getValueNodeVisitor } from '../../src'; test('it returns an array of all resolved value nodes', () => { const node = setValueNode([numberValueNode(1), numberValueNode(2), numberValueNode(3)]); const result = visit(node, getValueNodeVisitor(new LinkableDictionary())); expect(result).toStrictEqual([1, 2, 3]); }); ================================================ FILE: packages/dynamic-codecs/test/values/SomeValueNode.test.ts ================================================ import { someValueNode, stringValueNode } from '@codama/nodes'; import { LinkableDictionary, visit } from '@codama/visitors-core'; import { expect, test } from 'vitest'; import { getValueNodeVisitor } from '../../src'; test('it wraps the underlying value in a value object', () => { const result = visit(someValueNode(stringValueNode('Hello World!')), getValueNodeVisitor(new LinkableDictionary())); expect(result).toStrictEqual({ __option: 'Some', value: 'Hello World!' }); }); ================================================ FILE: packages/dynamic-codecs/test/values/StringValueNode.test.ts ================================================ import { stringValueNode } from '@codama/nodes'; import { LinkableDictionary, visit } from '@codama/visitors-core'; import { expect, test } from 'vitest'; import { getValueNodeVisitor } from '../../src'; test('it returns the string as-is', () => { const result = visit(stringValueNode('Hello World!'), getValueNodeVisitor(new LinkableDictionary())); expect(result).toBe('Hello World!'); }); ================================================ FILE: packages/dynamic-codecs/test/values/StructValueNode.test.ts ================================================ import { numberValueNode, stringValueNode, structFieldValueNode, structValueNode } from '@codama/nodes'; import { LinkableDictionary, visit } from '@codama/visitors-core'; import { expect, test } from 'vitest'; import { getValueNodeVisitor } from '../../src'; test('it returns struct values as objects', () => { const node = structValueNode([ structFieldValueNode('firstname', stringValueNode('John')), structFieldValueNode('age', numberValueNode(42)), ]); const result = visit(node, getValueNodeVisitor(new LinkableDictionary())); expect(result).toStrictEqual({ age: 42, firstname: 'John' }); }); ================================================ FILE: packages/dynamic-codecs/test/values/TupleValueNode.test.ts ================================================ import { booleanValueNode, numberValueNode, stringValueNode, tupleValueNode } from '@codama/nodes'; import { LinkableDictionary, visit } from '@codama/visitors-core'; import { expect, test } from 'vitest'; import { getValueNodeVisitor } from '../../src'; test('it returns the tuple as an array of values', () => { const node = tupleValueNode([numberValueNode(42), stringValueNode('Hello'), booleanValueNode(true)]); const result = visit(node, getValueNodeVisitor(new LinkableDictionary())); expect(result).toStrictEqual([42, 'Hello', true]); }); ================================================ FILE: packages/dynamic-codecs/tsconfig.declarations.json ================================================ { "compilerOptions": { "declaration": true, "declarationMap": true, "emitDeclarationOnly": true, "outDir": "./dist/types" }, "extends": "./tsconfig.json", "include": ["src/index.ts", "src/types"] } ================================================ FILE: packages/dynamic-codecs/tsconfig.json ================================================ { "$schema": "https://json.schemastore.org/tsconfig", "compilerOptions": { "lib": [] }, "display": "@codama/dynamic-codecs", "extends": "../../tsconfig.json", "include": ["src", "test"] } ================================================ FILE: packages/dynamic-codecs/tsup.config.ts ================================================ import { defineConfig } from 'tsup'; import { getPackageBuildConfigs } from '../../tsup.config.base'; export default defineConfig(getPackageBuildConfigs()); ================================================ FILE: packages/dynamic-codecs/vitest.config.mts ================================================ import { defineConfig } from 'vitest/config'; import { getVitestConfig } from '../../vitest.config.base.mjs'; export default defineConfig({ test: { projects: [getVitestConfig('browser'), getVitestConfig('node'), getVitestConfig('react-native')], }, }); ================================================ FILE: packages/dynamic-parsers/.gitignore ================================================ dist/ ================================================ FILE: packages/dynamic-parsers/.prettierignore ================================================ dist/ test/e2e/ test-ledger/ target/ CHANGELOG.md ================================================ FILE: packages/dynamic-parsers/LICENSE ================================================ MIT License Copyright (c) 2025 Codama Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: packages/dynamic-parsers/README.md ================================================ # Codama ➤ Dynamic Parsers [![npm][npm-image]][npm-url] [![npm-downloads][npm-downloads-image]][npm-url] [npm-downloads-image]: https://img.shields.io/npm/dm/@codama/dynamic-parsers.svg?style=flat [npm-image]: https://img.shields.io/npm/v/@codama/dynamic-parsers.svg?style=flat&label=%40codama%2Fdynamic-parsers [npm-url]: https://www.npmjs.com/package/@codama/dynamic-parsers This package provides a set of helpers that, given any Codama IDL, dynamically identifies and parses any byte array into deserialized accounts, events, and instructions. ## Installation ```sh pnpm install @codama/dynamic-parsers ``` > [!NOTE] > This package is **not** included in the main [`codama`](../library) package. ## Types ### `ParsedData` This type represents the result of identifying and parsing a byte array from a given root node. It provides us with the full `NodePath` of the identified node, as well as the data deserialized from the provided bytes. ```ts type ParsedData = { data: unknown; path: NodePath; }; ``` ## Functions ### `parseAccountData(rootNode, bytes)` Given a `RootNode` and a byte array, this function will attempt to identify the correct account node and use it to deserialize the provided bytes. Therefore, it returns a `ParsedData` object if the parsing was successful, or `undefined` otherwise. ```ts const parsedData = parseAccountData(rootNode, bytes); // ^ ParsedData | undefined if (parsedData) { const accountNode: AccountNode = getLastNodeFromPath(parsedData.path); const decodedData: unknown = parsedData.data; } ``` ### `parseEventData(rootNode, bytes)` Similarly to `parseAccountData`, this function will match the provided bytes to an event node and deserialize them accordingly. It returns a `ParsedData` object if the parsing was successful, or `undefined` otherwise. ```ts const parsedData = parseEventData(rootNode, bytes); // ^ ParsedData | undefined if (parsedData) { const eventNode: EventNode = getLastNodeFromPath(parsedData.path); const decodedData: unknown = parsedData.data; } ``` ### `parseInstructionData(rootNode, bytes)` Similarly to `parseAccountData`, this function will match the provided bytes to an instruction node and deserialize them accordingly. It returns a `ParsedData` object if the parsing was successful, or `undefined` otherwise. ```ts const parsedData = parseInstructionData(rootNode, bytes); // ^ ParsedData | undefined if (parsedData) { const instructionNode: InstructionNode = getLastNodeFromPath(parsedData.path); const decodedData: unknown = parsedData.data; } ``` ### `parseInstruction(rootNode, instruction)` This function accepts a `RootNode` and an `Instruction` type — as defined in `@solana/instructions` — in order to return a `ParsedData` object that also includes an `accounts` array that match each `AccountMeta` with its corresponding account name. ```ts const parsedData = parseInstruction(rootNode, instruction); if (parsedData) { const namedAccounts = parsedData.accounts; // ^ Array } ``` ### `identifyAccountData` This function tries to match the provided bytes to an account node, returning a `NodePath` object if the identification was successful, or `undefined` otherwise. It is used by the `parseAccountData` function under the hood. ```ts const path = identifyAccountData(root, bytes); // ^ NodePath | undefined if (path) { const accountNode: AccountNode = getLastNodeFromPath(path); } ``` ### `identifyInstructionData` This function tries to match the provided bytes to an instruction node, returning a `NodePath` object if the identification was successful, or `undefined` otherwise. It is used by the `parseInstructionData` function under the hood. ```ts const path = identifyInstructionData(root, bytes); // ^ NodePath | undefined if (path) { const instructionNode: InstructionNode = getLastNodeFromPath(path); } ``` ### `identifyEventData` This function tries to match the provided bytes to an event node, returning a `NodePath` object if the identification was successful, or `undefined` otherwise. It is used by the `parseEventData` function under the hood. ```ts const path = identifyEventData(root, bytes); // ^ NodePath | undefined if (path) { const eventNode: EventNode = getLastNodeFromPath(path); } ``` ================================================ FILE: packages/dynamic-parsers/package.json ================================================ { "name": "@codama/dynamic-parsers", "version": "1.2.0", "description": "Helpers to dynamically identify and parse accounts and instructions", "exports": { "types": "./dist/types/index.d.ts", "react-native": "./dist/index.react-native.mjs", "browser": { "import": "./dist/index.browser.mjs", "require": "./dist/index.browser.cjs" }, "node": { "import": "./dist/index.node.mjs", "require": "./dist/index.node.cjs" } }, "browser": { "./dist/index.node.cjs": "./dist/index.browser.cjs", "./dist/index.node.mjs": "./dist/index.browser.mjs" }, "main": "./dist/index.node.cjs", "module": "./dist/index.node.mjs", "react-native": "./dist/index.react-native.mjs", "types": "./dist/types/index.d.ts", "type": "commonjs", "files": [ "./dist/types", "./dist/index.*" ], "sideEffects": false, "keywords": [ "solana", "framework", "standard", "specifications", "parsers" ], "scripts": { "build": "rimraf dist && tsup && tsc -p ./tsconfig.declarations.json", "dev": "vitest --project node", "lint": "eslint . && prettier --check .", "lint:fix": "eslint --fix . && prettier --write .", "test": "pnpm test:types && pnpm test:treeshakability && pnpm test:unit", "test:treeshakability": "for file in dist/index.*.mjs; do agadoo $file; done", "test:types": "tsc --noEmit", "test:unit": "vitest run" }, "dependencies": { "@codama/dynamic-codecs": "workspace:*", "@codama/errors": "workspace:*", "@codama/nodes": "workspace:*", "@codama/visitors-core": "workspace:*", "@solana/instructions": "^5.3.0" }, "devDependencies": { "@solana/codecs": "^5.3.0" }, "license": "MIT", "repository": { "type": "git", "url": "https://github.com/codama-idl/codama" }, "bugs": { "url": "http://github.com/codama-idl/codama/issues" }, "browserslist": [ "supports bigint and not dead", "maintained node versions" ] } ================================================ FILE: packages/dynamic-parsers/src/discriminators.ts ================================================ import { CodecAndValueVisitors, containsBytes, ReadonlyUint8Array } from '@codama/dynamic-codecs'; import { CODAMA_ERROR__DISCRIMINATOR_FIELD_HAS_NO_DEFAULT_VALUE, CODAMA_ERROR__DISCRIMINATOR_FIELD_NOT_FOUND, CodamaError, } from '@codama/errors'; import { assertIsNode, ConstantDiscriminatorNode, constantDiscriminatorNode, constantValueNode, DiscriminatorNode, FieldDiscriminatorNode, isNode, SizeDiscriminatorNode, StructTypeNode, TypeNode, } from '@codama/nodes'; import { visit } from '@codama/visitors-core'; export function matchDiscriminators( bytes: ReadonlyUint8Array, discriminators: DiscriminatorNode[], typeNode: TypeNode, visitors: CodecAndValueVisitors, ): boolean { return ( discriminators.length > 0 && discriminators.every(discriminator => matchDiscriminator(bytes, discriminator, typeNode, visitors)) ); } function matchDiscriminator( bytes: ReadonlyUint8Array, discriminator: DiscriminatorNode, typeNode: TypeNode, visitors: CodecAndValueVisitors, ): boolean { if (isNode(discriminator, 'constantDiscriminatorNode')) { return matchConstantDiscriminator(bytes, discriminator, visitors); } if (isNode(discriminator, 'fieldDiscriminatorNode')) { return matchFieldDiscriminator(bytes, discriminator, typeNode, visitors); } assertIsNode(discriminator, 'sizeDiscriminatorNode'); return matchSizeDiscriminator(bytes, discriminator); } function matchConstantDiscriminator( bytes: ReadonlyUint8Array, discriminator: ConstantDiscriminatorNode, { codecVisitor, valueVisitor }: CodecAndValueVisitors, ): boolean { const codec = visit(discriminator.constant.type, codecVisitor); const value = visit(discriminator.constant.value, valueVisitor); const bytesToMatch = codec.encode(value); return containsBytes(bytes, bytesToMatch, discriminator.offset); } function matchFieldDiscriminator( bytes: ReadonlyUint8Array, discriminator: FieldDiscriminatorNode, typeNode: TypeNode, visitors: CodecAndValueVisitors, ): boolean { if (!isNode(typeNode, 'structTypeNode')) { throw new CodamaError(CODAMA_ERROR__DISCRIMINATOR_FIELD_NOT_FOUND, { field: discriminator.name, }); } const struct = typeNode as StructTypeNode; const field = struct.fields.find(field => field.name === discriminator.name); if (!field) { throw new CodamaError(CODAMA_ERROR__DISCRIMINATOR_FIELD_NOT_FOUND, { field: discriminator.name, }); } if (!field.defaultValue) { throw new CodamaError(CODAMA_ERROR__DISCRIMINATOR_FIELD_HAS_NO_DEFAULT_VALUE, { field: discriminator.name, }); } const constantNode = constantValueNode(field.type, field.defaultValue); const constantDiscriminator = constantDiscriminatorNode(constantNode, discriminator.offset); return matchConstantDiscriminator(bytes, constantDiscriminator, visitors); } function matchSizeDiscriminator(bytes: ReadonlyUint8Array, discriminator: SizeDiscriminatorNode): boolean { return bytes.length === discriminator.size; } ================================================ FILE: packages/dynamic-parsers/src/identify.ts ================================================ import { CodecAndValueVisitors, getCodecAndValueVisitors, ReadonlyUint8Array } from '@codama/dynamic-codecs'; import { AccountNode, EventNode, GetNodeFromKind, InstructionNode, isNodeFilter, resolveNestedTypeNode, RootNode, structTypeNodeFromInstructionArgumentNodes, } from '@codama/nodes'; import { getRecordLinkablesVisitor, LinkableDictionary, NodePath, NodeStack, pipe, recordNodeStackVisitor, visit, Visitor, } from '@codama/visitors-core'; import { matchDiscriminators } from './discriminators'; export function identifyAccountData( root: RootNode, bytes: ReadonlyUint8Array | Uint8Array, ): NodePath | undefined { return identifyData(root, bytes, 'accountNode'); } export function identifyEventData( root: RootNode, bytes: ReadonlyUint8Array | Uint8Array, ): NodePath | undefined { return identifyData(root, bytes, 'eventNode'); } export function identifyInstructionData( root: RootNode, bytes: ReadonlyUint8Array | Uint8Array, ): NodePath | undefined { return identifyData(root, bytes, 'instructionNode'); } export function identifyData( root: RootNode, bytes: ReadonlyUint8Array | Uint8Array, kind?: TKind | TKind[], ): NodePath> | undefined { const stack = new NodeStack(); const linkables = new LinkableDictionary(); visit(root, getRecordLinkablesVisitor(linkables)); const codecAndValueVisitors = getCodecAndValueVisitors(linkables, { stack }); const visitor = getByteIdentificationVisitor( kind ?? (['accountNode', 'instructionNode', 'eventNode'] as TKind[]), bytes, codecAndValueVisitors, { stack }, ); return visit(root, visitor); } export function getByteIdentificationVisitor( kind: TKind | TKind[], bytes: ReadonlyUint8Array | Uint8Array, codecAndValueVisitors: CodecAndValueVisitors, options: { stack?: NodeStack } = {}, ) { const stack = options.stack ?? new NodeStack(); return pipe( { visitAccount(node) { if (!node.discriminators) return; const struct = resolveNestedTypeNode(node.data); const match = matchDiscriminators(bytes, node.discriminators, struct, codecAndValueVisitors); return match ? stack.getPath(node.kind) : undefined; }, visitEvent(node) { if (!node.discriminators) return; const match = matchDiscriminators( bytes, node.discriminators, resolveNestedTypeNode(node.data), codecAndValueVisitors, ); return match ? stack.getPath(node.kind) : undefined; }, visitInstruction(node) { if (!node.discriminators) return; const struct = structTypeNodeFromInstructionArgumentNodes(node.arguments); const match = matchDiscriminators(bytes, node.discriminators, struct, codecAndValueVisitors); return match ? stack.getPath(node.kind) : undefined; }, visitProgram(node) { const candidates = [...node.accounts, ...node.events, ...node.instructions].filter(isNodeFilter(kind)); for (const candidate of candidates) { const result = visit(candidate, this); if (result) return result; } }, visitRoot(node) { return visit(node.program, this); }, } as Visitor< NodePath> | undefined, 'accountNode' | 'eventNode' | 'instructionNode' | 'programNode' | 'rootNode' >, v => recordNodeStackVisitor(v, stack), ); } ================================================ FILE: packages/dynamic-parsers/src/index.ts ================================================ export * from './identify'; export * from './parsers'; ================================================ FILE: packages/dynamic-parsers/src/parsers.ts ================================================ import { getNodeCodec, ReadonlyUint8Array } from '@codama/dynamic-codecs'; import { AccountNode, CamelCaseString, EventNode, GetNodeFromKind, InstructionNode, RootNode } from '@codama/nodes'; import { getLastNodeFromPath, NodePath } from '@codama/visitors-core'; import type { AccountLookupMeta, AccountMeta, Instruction, InstructionWithAccounts, InstructionWithData, } from '@solana/instructions'; import { identifyData } from './identify'; type ParsableNode = AccountNode | EventNode | InstructionNode; type ParsableNodeKind = ParsableNode['kind']; export type ParsedData = { data: unknown; path: NodePath; }; export function parseAccountData( root: RootNode, bytes: ReadonlyUint8Array | Uint8Array, ): ParsedData | undefined { return parseData(root, bytes, 'accountNode'); } export function parseEventData( root: RootNode, bytes: ReadonlyUint8Array | Uint8Array, ): ParsedData | undefined { return parseData(root, bytes, 'eventNode'); } export function parseInstructionData( root: RootNode, bytes: ReadonlyUint8Array | Uint8Array, ): ParsedData | undefined { return parseData(root, bytes, 'instructionNode'); } export function parseData( root: RootNode, bytes: ReadonlyUint8Array | Uint8Array, kind?: TKind | TKind[], ): ParsedData> | undefined { const path = identifyData(root, bytes, kind ?? (['accountNode', 'instructionNode', 'eventNode'] as TKind[])); if (!path) return undefined; const codec = getNodeCodec(path as NodePath); const data = codec.decode(bytes); return { data, path }; } type ParsedInstructionAccounts = ReadonlyArray; type ParsedInstruction = ParsedData & { accounts: ParsedInstructionAccounts }; export function parseInstruction( root: RootNode, instruction: Instruction & InstructionWithAccounts & InstructionWithData, ): ParsedInstruction | undefined { const parsedData = parseInstructionData(root, instruction.data); if (!parsedData) return undefined; const instructionNode = getLastNodeFromPath(parsedData.path); const accounts: ParsedInstructionAccounts = instructionNode.accounts.flatMap((account, index) => { const accountMeta = instruction.accounts[index]; if (!accountMeta) return []; return [{ ...accountMeta, name: account.name }]; }); return { ...parsedData, accounts }; } ================================================ FILE: packages/dynamic-parsers/src/types/global.d.ts ================================================ declare const __BROWSER__: boolean; declare const __ESM__: boolean; declare const __NODEJS__: boolean; declare const __REACTNATIVE__: boolean; declare const __TEST__: boolean; declare const __VERSION__: string; ================================================ FILE: packages/dynamic-parsers/test/_setup.ts ================================================ import { getBase16Encoder, ReadonlyUint8Array } from '@solana/codecs'; export function hex(hexadecimal: string): ReadonlyUint8Array { return getBase16Encoder().encode(hexadecimal); } ================================================ FILE: packages/dynamic-parsers/test/discriminators.test.ts ================================================ import { CodecAndValueVisitors, getCodecAndValueVisitors } from '@codama/dynamic-codecs'; import { CODAMA_ERROR__DISCRIMINATOR_FIELD_HAS_NO_DEFAULT_VALUE, CODAMA_ERROR__DISCRIMINATOR_FIELD_NOT_FOUND, CodamaError, } from '@codama/errors'; import { accountNode, constantDiscriminatorNode, constantValueNode, constantValueNodeFromBytes, definedTypeLinkNode, definedTypeNode, fieldDiscriminatorNode, fixedSizeTypeNode, numberTypeNode, numberValueNode, programLinkNode, programNode, rootNode, sizeDiscriminatorNode, stringTypeNode, structFieldTypeNode, structTypeNode, } from '@codama/nodes'; import { getRecordLinkablesVisitor, LinkableDictionary, NodeStack, visit } from '@codama/visitors-core'; import { beforeEach, describe, expect, test } from 'vitest'; import { matchDiscriminators } from '../src/discriminators'; import { hex } from './_setup'; describe('matchDiscriminators', () => { let linkables: LinkableDictionary; let codecAndValueVisitors: CodecAndValueVisitors; beforeEach(() => { linkables = new LinkableDictionary(); codecAndValueVisitors = getCodecAndValueVisitors(linkables); }); test('it does not match if no discriminators are provided', () => { const result = matchDiscriminators(hex('ff'), [], structTypeNode([]), codecAndValueVisitors); expect(result).toBe(false); }); describe('size discriminators', () => { test('it returns true if the size matches exactly', () => { const result = matchDiscriminators( hex('0102030405'), [sizeDiscriminatorNode(5)], structTypeNode([]), codecAndValueVisitors, ); expect(result).toBe(true); }); test('it returns false if the size is lower', () => { const result = matchDiscriminators( hex('01020304'), [sizeDiscriminatorNode(5)], structTypeNode([]), codecAndValueVisitors, ); expect(result).toBe(false); }); test('it returns false if the size is greater', () => { const result = matchDiscriminators( hex('010203040506'), [sizeDiscriminatorNode(5)], structTypeNode([]), codecAndValueVisitors, ); expect(result).toBe(false); }); }); describe('constant discriminators', () => { test('it returns true if the bytes start with the provided constant', () => { const discriminator = constantDiscriminatorNode(constantValueNodeFromBytes('base16', 'ff')); const result = matchDiscriminators( hex('ff0102030405'), [discriminator], structTypeNode([]), codecAndValueVisitors, ); expect(result).toBe(true); }); test('it returns false if the bytes do not start with the provided constant', () => { const discriminator = constantDiscriminatorNode(constantValueNodeFromBytes('base16', 'ff')); const result = matchDiscriminators( hex('aa0102030405'), [discriminator], structTypeNode([]), codecAndValueVisitors, ); expect(result).toBe(false); }); test('it returns true if the bytes match with the provided constant at the given offset', () => { const discriminator = constantDiscriminatorNode( constantValueNodeFromBytes('base16', 'ff'), 3 /** offset */, ); const result = matchDiscriminators( hex('010203ff0405'), [discriminator], structTypeNode([]), codecAndValueVisitors, ); expect(result).toBe(true); }); test('it returns false if the bytes do not match with the provided constant at the given offset', () => { const discriminator = constantDiscriminatorNode( constantValueNodeFromBytes('base16', 'ff'), 3 /** offset */, ); const result = matchDiscriminators( hex('010203aa0405'), [discriminator], structTypeNode([]), codecAndValueVisitors, ); expect(result).toBe(false); }); test('it resolves link nodes correctly', () => { // Given two link nodes designed so that the path would // fail if we did not save and restored linked paths. const discriminator = constantDiscriminatorNode( constantValueNode(definedTypeLinkNode('typeB1', programLinkNode('programB')), numberValueNode(42)), ); const programA = programNode({ accounts: [accountNode({ discriminators: [discriminator], name: 'myAccount' })], definedTypes: [ definedTypeNode({ name: 'typeA', type: definedTypeLinkNode('typeB1', programLinkNode('programB')), }), ], name: 'programA', publicKey: '1111', }); const programB = programNode({ definedTypes: [ definedTypeNode({ name: 'typeB1', type: definedTypeLinkNode('typeB2') }), definedTypeNode({ name: 'typeB2', type: numberTypeNode('u32') }), ], name: 'programB', publicKey: '2222', }); const root = rootNode(programA, [programB]); // And given a recorded linkables dictionary. const linkables = new LinkableDictionary(); visit(root, getRecordLinkablesVisitor(linkables)); // And a stack keeping track of the current visited nodes. const stack = new NodeStack([root, programA, programA.accounts[0]]); codecAndValueVisitors = getCodecAndValueVisitors(linkables, { stack }); // When we match the discriminator which should resolve to a u32 number equal to 42. const result = matchDiscriminators( hex('2a0000000102030405'), [discriminator], structTypeNode([]), codecAndValueVisitors, ); // Then we expect the discriminator to match. expect(result).toBe(true); }); }); describe('field discriminators', () => { test('it returns true if the bytes start with the provided field default value', () => { const discriminator = fieldDiscriminatorNode('key'); const fields = structTypeNode([ structFieldTypeNode({ defaultValue: numberValueNode(0xff), name: 'key', type: numberTypeNode('u8'), }), ]); const result = matchDiscriminators(hex('ff0102030405'), [discriminator], fields, codecAndValueVisitors); expect(result).toBe(true); }); test('it returns false if the bytes do not start with the provided field default value', () => { const discriminator = fieldDiscriminatorNode('key'); const fields = structTypeNode([ structFieldTypeNode({ defaultValue: numberValueNode(0xff), name: 'key', type: numberTypeNode('u8'), }), ]); const result = matchDiscriminators(hex('aa0102030405'), [discriminator], fields, codecAndValueVisitors); expect(result).toBe(false); }); test('it returns true if the bytes match with the provided field default value at the given offset', () => { const discriminator = fieldDiscriminatorNode('key', 3 /** offset */); const fields = structTypeNode([ structFieldTypeNode({ name: 'id', type: fixedSizeTypeNode(stringTypeNode('utf8'), 3) }), structFieldTypeNode({ defaultValue: numberValueNode(0xff), name: 'key', type: numberTypeNode('u8'), }), ]); const result = matchDiscriminators(hex('010203ff0405'), [discriminator], fields, codecAndValueVisitors); expect(result).toBe(true); }); test('it returns false if the bytes do not match with the provided field default value at the given offset', () => { const discriminator = fieldDiscriminatorNode('key', 3 /** offset */); const fields = structTypeNode([ structFieldTypeNode({ name: 'id', type: fixedSizeTypeNode(stringTypeNode('utf8'), 3) }), structFieldTypeNode({ defaultValue: numberValueNode(0xff), name: 'key', type: numberTypeNode('u8'), }), ]); const result = matchDiscriminators(hex('010203aa0405'), [discriminator], fields, codecAndValueVisitors); expect(result).toBe(false); }); test('it throws an error if the discriminator field is not found', () => { const discriminator = fieldDiscriminatorNode('key'); const fields = structTypeNode([]); expect(() => matchDiscriminators(hex('0102030405'), [discriminator], fields, codecAndValueVisitors), ).toThrow(new CodamaError(CODAMA_ERROR__DISCRIMINATOR_FIELD_NOT_FOUND, { field: 'key' })); }); test('it throws an error if the discriminator field does not have a default value', () => { const discriminator = fieldDiscriminatorNode('key'); const fields = structTypeNode([ structFieldTypeNode({ name: 'key', type: numberTypeNode('u8'), }), ]); expect(() => matchDiscriminators(hex('0102030405'), [discriminator], fields, codecAndValueVisitors), ).toThrow(new CodamaError(CODAMA_ERROR__DISCRIMINATOR_FIELD_HAS_NO_DEFAULT_VALUE, { field: 'key' })); }); test('it resolves link nodes correctly', () => { // Given two link nodes designed so that the path would // fail if we did not save and restored linked paths. const discriminator = fieldDiscriminatorNode('key'); const fields = structTypeNode([ structFieldTypeNode({ defaultValue: numberValueNode(42), name: 'key', type: definedTypeLinkNode('typeB1', programLinkNode('programB')), }), ]); const programA = programNode({ accounts: [accountNode({ data: fields, discriminators: [discriminator], name: 'myAccount' })], definedTypes: [ definedTypeNode({ name: 'typeA', type: definedTypeLinkNode('typeB1', programLinkNode('programB')), }), ], name: 'programA', publicKey: '1111', }); const programB = programNode({ definedTypes: [ definedTypeNode({ name: 'typeB1', type: definedTypeLinkNode('typeB2') }), definedTypeNode({ name: 'typeB2', type: numberTypeNode('u32') }), ], name: 'programB', publicKey: '2222', }); const root = rootNode(programA, [programB]); // And given a recorded linkables dictionary. const linkables = new LinkableDictionary(); visit(root, getRecordLinkablesVisitor(linkables)); // And a stack keeping track of the current visited nodes. const stack = new NodeStack([root, programA, programA.accounts[0]]); codecAndValueVisitors = getCodecAndValueVisitors(linkables, { stack }); // When we match the discriminator which should resolve to a u32 number equal to 42. const result = matchDiscriminators( hex('2a0000000102030405'), [discriminator], fields, codecAndValueVisitors, ); // Then we expect the discriminator to match. expect(result).toBe(true); }); }); describe('multiple discriminators', () => { test('it returns true if all discriminators match', () => { const result = matchDiscriminators( hex('ff0102030405'), [constantDiscriminatorNode(constantValueNodeFromBytes('base16', 'ff')), sizeDiscriminatorNode(6)], structTypeNode([]), codecAndValueVisitors, ); expect(result).toBe(true); }); test('it returns false if any discriminator does not match', () => { const result = matchDiscriminators( hex('ff0102030405'), [constantDiscriminatorNode(constantValueNodeFromBytes('base16', 'ff')), sizeDiscriminatorNode(999)], structTypeNode([]), codecAndValueVisitors, ); expect(result).toBe(false); }); test('it can match on all discriminator types', () => { const result = matchDiscriminators( hex('aabb01020304'), [ fieldDiscriminatorNode('key'), constantDiscriminatorNode(constantValueNodeFromBytes('base16', 'bb'), 1), sizeDiscriminatorNode(6), ], structTypeNode([ structFieldTypeNode({ defaultValue: numberValueNode(0xaa), name: 'key', type: numberTypeNode('u8'), }), ]), codecAndValueVisitors, ); expect(result).toBe(true); }); }); }); ================================================ FILE: packages/dynamic-parsers/test/identify.test.ts ================================================ import { accountNode, bytesTypeNode, constantDiscriminatorNode, constantValueNode, constantValueNodeFromBytes, eventNode, fixedSizeTypeNode, hiddenPrefixTypeNode, instructionNode, numberTypeNode, programNode, rootNode, sizeDiscriminatorNode, structTypeNode, tupleTypeNode, } from '@codama/nodes'; import { describe, expect, test } from 'vitest'; import { identifyAccountData, identifyEventData, identifyInstructionData } from '../src'; import { hex } from './_setup'; describe('identifyAccountData', () => { test('it identifies an account using its discriminator nodes', () => { const root = rootNode( programNode({ accounts: [accountNode({ discriminators: [sizeDiscriminatorNode(4)], name: 'myAccount' })], name: 'myProgram', publicKey: '1111', }), ); const result = identifyAccountData(root, hex('01020304')); expect(result).toStrictEqual([root, root.program, root.program.accounts[0]]); }); test('it fails to identify accounts whose discriminator nodes do not match the given data', () => { const root = rootNode( programNode({ accounts: [accountNode({ discriminators: [sizeDiscriminatorNode(999)], name: 'myAccount' })], name: 'myProgram', publicKey: '1111', }), ); const result = identifyAccountData(root, hex('01020304')); expect(result).toBeUndefined(); }); test('it fails to identify accounts with no discriminator nodes', () => { const root = rootNode( programNode({ accounts: [accountNode({ name: 'myAccount' })], name: 'myProgram', publicKey: '1111' }), ); const result = identifyAccountData(root, hex('01020304')); expect(result).toBeUndefined(); }); test('it identifies the first matching account if multiple accounts match', () => { const root = rootNode( programNode({ accounts: [ accountNode({ discriminators: [sizeDiscriminatorNode(4)], name: 'accountA', }), accountNode({ discriminators: [constantDiscriminatorNode(constantValueNodeFromBytes('base16', 'ff'))], name: 'accountB', }), ], name: 'myProgram', publicKey: '1111', }), ); const result = identifyAccountData(root, hex('ff010203')); expect(result).toStrictEqual([root, root.program, root.program.accounts[0]]); }); test('it does not identify accounts in additional programs', () => { const root = rootNode(programNode({ name: 'myProgram', publicKey: '1111' }), [ programNode({ accounts: [accountNode({ discriminators: [sizeDiscriminatorNode(4)], name: 'myAccount' })], name: 'myProgram', publicKey: '1111', }), ]); const result = identifyAccountData(root, hex('01020304')); expect(result).toBeUndefined(); }); test('it does not identify accounts using instruction discriminators', () => { const root = rootNode(programNode({ name: 'myProgram', publicKey: '1111' }), [ programNode({ instructions: [instructionNode({ discriminators: [sizeDiscriminatorNode(4)], name: 'myInstruction' })], name: 'myProgram', publicKey: '1111', }), ]); const result = identifyAccountData(root, hex('01020304')); expect(result).toBeUndefined(); }); }); describe('identifyInstructionData', () => { test('it identifies an instruction using its discriminator nodes', () => { const root = rootNode( programNode({ instructions: [instructionNode({ discriminators: [sizeDiscriminatorNode(4)], name: 'myInstruction' })], name: 'myProgram', publicKey: '1111', }), ); const result = identifyInstructionData(root, hex('01020304')); expect(result).toStrictEqual([root, root.program, root.program.instructions[0]]); }); test('it fails to identify instructions whose discriminator nodes do not match the given data', () => { const root = rootNode( programNode({ instructions: [ instructionNode({ discriminators: [sizeDiscriminatorNode(999)], name: 'myInstruction' }), ], name: 'myProgram', publicKey: '1111', }), ); const result = identifyInstructionData(root, hex('01020304')); expect(result).toBeUndefined(); }); test('it fails to identify instructions with no discriminator nodes', () => { const root = rootNode( programNode({ instructions: [instructionNode({ name: 'myInstruction' })], name: 'myProgram', publicKey: '1111', }), ); const result = identifyInstructionData(root, hex('01020304')); expect(result).toBeUndefined(); }); test('it identifies the first matching instruction if multiple instructions match', () => { const root = rootNode( programNode({ instructions: [ instructionNode({ discriminators: [sizeDiscriminatorNode(4)], name: 'instructionA', }), instructionNode({ discriminators: [constantDiscriminatorNode(constantValueNodeFromBytes('base16', 'ff'))], name: 'instructionB', }), ], name: 'myProgram', publicKey: '1111', }), ); const result = identifyInstructionData(root, hex('ff010203')); expect(result).toStrictEqual([root, root.program, root.program.instructions[0]]); }); test('it does not identify instructions in additional programs', () => { const root = rootNode(programNode({ name: 'myProgram', publicKey: '1111' }), [ programNode({ instructions: [instructionNode({ discriminators: [sizeDiscriminatorNode(4)], name: 'myInstruction' })], name: 'myProgram', publicKey: '1111', }), ]); const result = identifyInstructionData(root, hex('01020304')); expect(result).toBeUndefined(); }); test('it does not identify instructions using account discriminators', () => { const root = rootNode(programNode({ name: 'myProgram', publicKey: '1111' }), [ programNode({ accounts: [accountNode({ discriminators: [sizeDiscriminatorNode(4)], name: 'myAccount' })], name: 'myProgram', publicKey: '1111', }), ]); const result = identifyInstructionData(root, hex('01020304')); expect(result).toBeUndefined(); }); }); describe('identifyEventData', () => { test('it identifies an event using its discriminator nodes', () => { const root = rootNode( programNode({ events: [ eventNode({ data: structTypeNode([]), discriminators: [sizeDiscriminatorNode(4)], name: 'myEvent', }), ], name: 'myProgram', publicKey: '1111', }), ); const result = identifyEventData(root, hex('01020304')); expect(result).toStrictEqual([root, root.program, root.program.events[0]]); }); test('it fails to identify events whose discriminator nodes do not match the given data', () => { const root = rootNode( programNode({ events: [ eventNode({ data: structTypeNode([]), discriminators: [sizeDiscriminatorNode(999)], name: 'myEvent', }), ], name: 'myProgram', publicKey: '1111', }), ); const result = identifyEventData(root, hex('01020304')); expect(result).toBeUndefined(); }); test('it fails to identify events with no discriminator nodes', () => { const root = rootNode( programNode({ events: [eventNode({ data: structTypeNode([]), name: 'myEvent' })], name: 'myProgram', publicKey: '1111', }), ); const result = identifyEventData(root, hex('01020304')); expect(result).toBeUndefined(); }); test('it does not identify events using instruction discriminators', () => { const root = rootNode( programNode({ instructions: [instructionNode({ discriminators: [sizeDiscriminatorNode(4)], name: 'myInstruction' })], name: 'myProgram', publicKey: '1111', }), ); const result = identifyEventData(root, hex('01020304')); expect(result).toBeUndefined(); }); test('it identifies tuple events using constant discriminators', () => { const root = rootNode( programNode({ events: [ eventNode({ data: hiddenPrefixTypeNode(tupleTypeNode([numberTypeNode('u32')]), [ constantValueNode( fixedSizeTypeNode(bytesTypeNode(), 2), constantValueNodeFromBytes('base16', '0102'), ), ]), discriminators: [ constantDiscriminatorNode( constantValueNode( fixedSizeTypeNode(bytesTypeNode(), 2), constantValueNodeFromBytes('base16', '0102'), ), ), ], name: 'tupleEvent', }), ], name: 'myProgram', publicKey: '1111', }), ); const result = identifyEventData(root, hex('01022a000000')); expect(result).toStrictEqual([root, root.program, root.program.events[0]]); }); }); ================================================ FILE: packages/dynamic-parsers/test/parsers.test.ts ================================================ import { accountNode, bytesTypeNode, constantDiscriminatorNode, constantValueNode, constantValueNodeFromBytes, eventNode, fieldDiscriminatorNode, fixedSizeTypeNode, hiddenPrefixTypeNode, instructionArgumentNode, instructionNode, numberTypeNode, numberValueNode, programNode, rootNode, sizePrefixTypeNode, stringTypeNode, structFieldTypeNode, structTypeNode, tupleTypeNode, } from '@codama/nodes'; import { describe, expect, test } from 'vitest'; import { parseAccountData, parseEventData, parseInstructionData } from '../src'; import { hex } from './_setup'; describe('parseAccountData', () => { test('it parses some account data from a root node', () => { const root = rootNode( programNode({ accounts: [ accountNode({ data: structTypeNode([ structFieldTypeNode({ defaultValue: numberValueNode(9), name: 'discriminator', type: numberTypeNode('u8'), }), structFieldTypeNode({ name: 'firstname', type: sizePrefixTypeNode(stringTypeNode('utf8'), numberTypeNode('u16')), }), structFieldTypeNode({ name: 'age', type: numberTypeNode('u8'), }), ]), discriminators: [fieldDiscriminatorNode('discriminator')], name: 'myAccount', }), ], name: 'myProgram', publicKey: '1111', }), ); const result = parseAccountData(root, hex('090500416c6963652a')); expect(result).toStrictEqual({ data: { age: 42, discriminator: 9, firstname: 'Alice' }, path: [root, root.program, root.program.accounts[0]], }); }); }); describe('parseInstructionData', () => { test('it parses some instruction data from a root node', () => { const root = rootNode( programNode({ instructions: [ instructionNode({ arguments: [ instructionArgumentNode({ defaultValue: numberValueNode(9), name: 'discriminator', type: numberTypeNode('u8'), }), instructionArgumentNode({ name: 'firstname', type: sizePrefixTypeNode(stringTypeNode('utf8'), numberTypeNode('u16')), }), instructionArgumentNode({ name: 'age', type: numberTypeNode('u8'), }), ], discriminators: [fieldDiscriminatorNode('discriminator')], name: 'myInstruction', }), ], name: 'myProgram', publicKey: '1111', }), ); const result = parseInstructionData(root, hex('090500416c6963652a')); expect(result).toStrictEqual({ data: { age: 42, discriminator: 9, firstname: 'Alice' }, path: [root, root.program, root.program.instructions[0]], }); }); }); describe('parseEventData', () => { test('it parses some event data from a root node', () => { const root = rootNode( programNode({ events: [ eventNode({ data: structTypeNode([ structFieldTypeNode({ defaultValue: numberValueNode(9), name: 'discriminator', type: numberTypeNode('u8'), }), structFieldTypeNode({ name: 'firstname', type: sizePrefixTypeNode(stringTypeNode('utf8'), numberTypeNode('u16')), }), structFieldTypeNode({ name: 'age', type: numberTypeNode('u8'), }), ]), discriminators: [fieldDiscriminatorNode('discriminator')], name: 'myEvent', }), ], name: 'myProgram', publicKey: '1111', }), ); const result = parseEventData(root, hex('090500416c6963652a')); expect(result).toStrictEqual({ data: { age: 42, discriminator: 9, firstname: 'Alice' }, path: [root, root.program, root.program.events[0]], }); }); test('it parses tuple event data from a root node', () => { const root = rootNode( programNode({ events: [ eventNode({ data: hiddenPrefixTypeNode(tupleTypeNode([numberTypeNode('u32')]), [ constantValueNode( fixedSizeTypeNode(bytesTypeNode(), 2), constantValueNodeFromBytes('base16', '0102'), ), ]), discriminators: [ constantDiscriminatorNode( constantValueNode( fixedSizeTypeNode(bytesTypeNode(), 2), constantValueNodeFromBytes('base16', '0102'), ), ), ], name: 'tupleEvent', }), ], name: 'myProgram', publicKey: '1111', }), ); const result = parseEventData(root, hex('01022a000000')); expect(result).toStrictEqual({ data: [42], path: [root, root.program, root.program.events[0]], }); }); }); ================================================ FILE: packages/dynamic-parsers/test/types/global.d.ts ================================================ declare const __BROWSER__: boolean; declare const __ESM__: boolean; declare const __NODEJS__: boolean; declare const __REACTNATIVE__: boolean; declare const __TEST__: boolean; declare const __VERSION__: string; ================================================ FILE: packages/dynamic-parsers/tsconfig.declarations.json ================================================ { "compilerOptions": { "declaration": true, "declarationMap": true, "emitDeclarationOnly": true, "outDir": "./dist/types" }, "extends": "./tsconfig.json", "include": ["src/index.ts", "src/types"] } ================================================ FILE: packages/dynamic-parsers/tsconfig.json ================================================ { "$schema": "https://json.schemastore.org/tsconfig", "compilerOptions": { "lib": [] }, "display": "@codama/dynamic-parsers", "extends": "../../tsconfig.json", "include": ["src", "test"] } ================================================ FILE: packages/dynamic-parsers/tsup.config.ts ================================================ import { defineConfig } from 'tsup'; import { getPackageBuildConfigs } from '../../tsup.config.base'; export default defineConfig(getPackageBuildConfigs()); ================================================ FILE: packages/dynamic-parsers/vitest.config.mts ================================================ import { defineConfig } from 'vitest/config'; import { getVitestConfig } from '../../vitest.config.base.mjs'; export default defineConfig({ test: { projects: [getVitestConfig('browser'), getVitestConfig('node'), getVitestConfig('react-native')], }, }); ================================================ FILE: packages/errors/.gitignore ================================================ dist/ ================================================ FILE: packages/errors/.prettierignore ================================================ dist/ test/e2e/ test-ledger/ target/ CHANGELOG.md ================================================ FILE: packages/errors/LICENSE ================================================ MIT License Copyright (c) 2025 Codama Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: packages/errors/README.md ================================================ # Codama ➤ Errors [![npm][npm-image]][npm-url] [![npm-downloads][npm-downloads-image]][npm-url] [npm-downloads-image]: https://img.shields.io/npm/dm/@codama/errors.svg?style=flat [npm-image]: https://img.shields.io/npm/v/@codama/errors.svg?style=flat&label=%40codama%2Ferrors [npm-url]: https://www.npmjs.com/package/@codama/errors This package defines a `CodamaError` class that accepts a specific error code and a context object based on that code. It enables us to catch and handle errors in a more structured way. ## Installation ```sh pnpm install @codama/errors ``` > [!NOTE] > This package is included in the main [`codama`](../library) package. Meaning, you already have access to its content if you are installing Codama this way. > > ```sh > pnpm install codama > ``` ## Reading error messages ### In development mode When the `NODE_ENV` environment variable is not set to `"production"`, every error message will be included in the bundle. As such, you will be able to read them in plain language wherever they appear. ### In production mode On the other hand, when `NODE_ENV` is set to `"production"`, error messages will be stripped from the bundle to save space. Only the error code will appear when an error is encountered. Follow the instructions in the error message to convert the error code back to the human-readable error message. For instance, to recover the error text for the error with code `123`: ```shell npx @codama/errors decode -- 123 ``` ## Catching errors When you catch a `CodamaError` and assert its error code using `isCodamaError()`, TypeScript will refine the error's context to the type associated with that error code. You can use that context to render useful error messages, or to make context-aware decisions that help your application to recover from the error. ```ts import { CODAMA_ERROR__UNEXPECTED_NODE_KIND, isCodamaError } from '@codama/errors'; try { const codama = createFromJson(jsonIdl); } catch (e) { if (isCodamaError(e, CODAMA_ERROR__UNEXPECTED_NODE_KIND)) { const { expectedKinds, kind, node } = e.context; // ... } else if (isCodamaError(e, CODAMA_ERROR__VERSION_MISMATCH)) { const { codamaVersion, rootVersion } = e.context; // ... } else { throw e; } } ``` ## Contributing ### Adding a new error To add a new error in Codama, follow these steps: 1. Add a new exported error code constant to `src/codes.ts`. Find the most appropriate group for your error and ensure it is appended to the end of that group. 2. Add that new constant to the `CodamaErrorCode` union in `src/codes.ts`. 3. If you would like the new error to encapsulate context about the error itself define that context in `src/context.ts`. 4. Add the error's message to `src/messages.ts`. Any context values that you defined above will be interpolated into the message wherever you write `$key`, where `key` is the index of a value in the context (eg. ``'Unrecognized node `$kind`.'``). 5. Publish a new version of `@codama/errors` using changesets — maintainers will handle this via tha changesets CI workflow. 6. Bump the version of `@codama/errors` or `codama` in the consumer package from which the error is thrown. ### Removing an error message - Don't remove errors. - Don't change the meaning of an error message. - Don't change or reorder error codes. - Don't change or remove members of an error's context. When an older client throws an error, we want to make sure that they can always decode the error. If you make any of the changes above, old clients will, by definition, not have received your changes. This could make the errors that they throw impossible to decode going forward. ================================================ FILE: packages/errors/bin/cli.cjs ================================================ #!/usr/bin/env -S node const run = require('../dist/cli.cjs').run; run(process.argv); ================================================ FILE: packages/errors/package.json ================================================ { "name": "@codama/errors", "version": "1.6.0", "description": "Error management for Codama", "exports": { "types": "./dist/types/index.d.ts", "react-native": "./dist/index.react-native.mjs", "browser": { "import": "./dist/index.browser.mjs", "require": "./dist/index.browser.cjs" }, "node": { "import": "./dist/index.node.mjs", "require": "./dist/index.node.cjs" } }, "browser": { "./dist/index.node.cjs": "./dist/index.browser.cjs", "./dist/index.node.mjs": "./dist/index.browser.mjs" }, "main": "./dist/index.node.cjs", "module": "./dist/index.node.mjs", "react-native": "./dist/index.react-native.mjs", "types": "./dist/types/index.d.ts", "type": "commonjs", "bin": "./bin/cli.cjs", "files": [ "./bin", "./dist/types", "./dist/cli.*", "./dist/index.*" ], "sideEffects": false, "keywords": [ "solana", "framework", "standard", "specifications" ], "scripts": { "build": "rimraf dist && tsup && tsc -p ./tsconfig.declarations.json", "dev": "vitest --project node", "lint": "eslint . && prettier --check .", "lint:fix": "eslint --fix . && prettier --write .", "test": "pnpm test:types && pnpm test:treeshakability && pnpm test:unit", "test:treeshakability": "for file in dist/index.*.mjs; do agadoo $file; done", "test:types": "tsc --noEmit", "test:unit": "vitest run" }, "dependencies": { "@codama/node-types": "workspace:*", "commander": "^14.0.2", "picocolors": "^1.1.1" }, "license": "MIT", "repository": { "type": "git", "url": "https://github.com/codama-idl/codama" }, "bugs": { "url": "http://github.com/codama-idl/codama/issues" }, "browserslist": [ "supports bigint and not dead", "maintained node versions" ] } ================================================ FILE: packages/errors/src/cli/index.ts ================================================ /** * Heavily inspired by @solana/errors. * @see https://github.com/anza-xyz/kit/blob/main/packages/errors */ import { Command, InvalidArgumentError } from 'commander'; import pico from 'picocolors'; import { version } from '../../package.json'; import { CodamaErrorCode } from '../codes'; import { decodeEncodedContext } from '../context'; import { getHumanReadableErrorMessage } from '../message-formatter'; import { CodamaErrorMessages } from '../messages'; const program = new Command(); program.name('@codama/errors').description('Decode Codama JavaScript errors thrown in production').version(version); program .command('decode') .description('Decode a `CodamaErrorCode` to a human-readable message') .argument('', 'numeric error code to decode', rawCode => { const code = parseInt(rawCode, 10); if (isNaN(code) || `${code}` !== rawCode) { throw new InvalidArgumentError('It must be an integer'); } if (!(code in CodamaErrorMessages)) { throw new InvalidArgumentError('There exists no error with that code'); } return code; }) .argument('[encodedContext]', 'encoded context to interpolate into the error message', encodedContext => { try { return decodeEncodedContext(encodedContext); } catch { throw new InvalidArgumentError('Encoded context malformed'); } }) .action((code: number, context: object | undefined) => { const header = codamaColor(pico.bold('[Decoded]') + ` Codama error code #${code}`); const message = getHumanReadableErrorMessage(code as CodamaErrorCode, context); console.log(`\n${header}\n ${message}`); if (context) { const contextHeader = pico.blue(pico.bold('[Context]')); const contextString = JSON.stringify(context, null, 4).split('\n').join('\n '); console.log(`\n${contextHeader}\n ${contextString}`); } }); export function run(argv: readonly string[]) { program.parse(argv); } function codamaColor(text: string): string { if (!pico.isColorSupported) return text; return `\x1b[38;2;231;171;97m${text}\x1b[0m`; } ================================================ FILE: packages/errors/src/codes.ts ================================================ /** * Heavily inspired by @solana/errors. * @see https://github.com/anza-xyz/kit/blob/main/packages/errors * * --- * * WARNING: * - Don't remove error codes * - Don't change or reorder error codes. * * Good naming conventions: * - Prefixing common errors — e.g. under the same package — can be a good way to namespace them. * - Use consistent names — e.g. choose `PDA` or `PROGRAM_DERIVED_ADDRESS` and stick with it. Ensure your names are consistent with existing error codes. The decision might have been made for you. * - Recommended prefixes and suffixes: * - `MALFORMED_`: Some input was not constructed properly. E.g. `MALFORMED_BASE58_ENCODED_ADDRESS`. * - `INVALID_`: Some input is invalid (other than because it was MALFORMED). E.g. `INVALID_NUMBER_OF_BYTES`. * - `EXPECTED_`: Some input was different than expected, no need to specify the "GOT" part unless necessary. E.g. `EXPECTED_DECODED_ACCOUNT`. * - `_CANNOT_`: Some operation cannot be performed or some input cannot be used due to some condition. E.g. `CANNOT_DECODE_EMPTY_BYTE_ARRAY` or `PDA_CANNOT_END_WITH_PDA_MARKER`. * - `_MUST_BE_`: Some condition must be true. E.g. `NONCE_TRANSACTION_FIRST_INSTRUCTION_MUST_BE_ADVANCE_NONCE`. * - `_FAILED_TO_`: Tried to perform some operation and failed. E.g. `FAILED_TO_DECODE_ACCOUNT`. * - `_NOT_FOUND`: Some operation lead to not finding something. E.g. `ACCOUNT_NOT_FOUND`. * - `_OUT_OF_RANGE`: Some value is out of range. E.g. `ENUM_DISCRIMINATOR_OUT_OF_RANGE`. * - `_EXCEEDED`: Some limit was exceeded. E.g. `PDA_MAX_SEED_LENGTH_EXCEEDED`. * - `_MISMATCH`: Some elements do not match. E.g. `ENCODER_DECODER_FIXED_SIZE_MISMATCH`. * - `_MISSING`: Some required input is missing. E.g. `TRANSACTION_FEE_PAYER_MISSING`. * - `_UNIMPLEMENTED`: Some required component is not available in the environment. E.g. `SUBTLE_CRYPTO_VERIFY_FUNCTION_UNIMPLEMENTED`. */ export const CODAMA_ERROR__UNRECOGNIZED_NODE_KIND = 1; export const CODAMA_ERROR__UNEXPECTED_NODE_KIND = 2; export const CODAMA_ERROR__UNEXPECTED_NESTED_NODE_KIND = 3; export const CODAMA_ERROR__LINKED_NODE_NOT_FOUND = 4; export const CODAMA_ERROR__NODE_FILESYSTEM_FUNCTION_UNAVAILABLE = 5; export const CODAMA_ERROR__VERSION_MISMATCH = 6; export const CODAMA_ERROR__UNRECOGNIZED_NUMBER_FORMAT = 7; export const CODAMA_ERROR__UNRECOGNIZED_BYTES_ENCODING = 8; export const CODAMA_ERROR__ENUM_VARIANT_NOT_FOUND = 9; export const CODAMA_ERROR__DISCRIMINATOR_FIELD_NOT_FOUND = 10; export const CODAMA_ERROR__DISCRIMINATOR_FIELD_HAS_NO_DEFAULT_VALUE = 11; // Visitors-related errors. // Reserve error codes in the range [1200000-1200999]. export const CODAMA_ERROR__VISITORS__CANNOT_ADD_DUPLICATED_PDA_NAMES = 1200000; export const CODAMA_ERROR__VISITORS__INVALID_PDA_SEED_VALUES = 1200001; export const CODAMA_ERROR__VISITORS__CYCLIC_DEPENDENCY_DETECTED_WHEN_RESOLVING_INSTRUCTION_DEFAULT_VALUES = 1200002; export const CODAMA_ERROR__VISITORS__CANNOT_USE_OPTIONAL_ACCOUNT_AS_PDA_SEED_VALUE = 1200003; export const CODAMA_ERROR__VISITORS__INVALID_INSTRUCTION_DEFAULT_VALUE_DEPENDENCY = 1200004; export const CODAMA_ERROR__VISITORS__ACCOUNT_FIELD_NOT_FOUND = 1200005; export const CODAMA_ERROR__VISITORS__INVALID_NUMBER_WRAPPER = 1200006; export const CODAMA_ERROR__VISITORS__CANNOT_EXTEND_MISSING_VISIT_FUNCTION = 1200007; export const CODAMA_ERROR__VISITORS__FAILED_TO_VALIDATE_NODE = 1200008; export const CODAMA_ERROR__VISITORS__INSTRUCTION_ENUM_ARGUMENT_NOT_FOUND = 1200009; export const CODAMA_ERROR__VISITORS__CANNOT_FLATTEN_STRUCT_WITH_CONFLICTING_ATTRIBUTES = 1200010; export const CODAMA_ERROR__VISITORS__RENDER_MAP_KEY_NOT_FOUND = 1200011; export const CODAMA_ERROR__VISITORS__CANNOT_REMOVE_LAST_PATH_IN_NODE_STACK = 1200012; // Anchor-related errors. // Reserve error codes in the range [2100000-2100999]. export const CODAMA_ERROR__ANCHOR__UNRECOGNIZED_IDL_TYPE = 2100000; export const CODAMA_ERROR__ANCHOR__ACCOUNT_TYPE_MISSING = 2100001; export const CODAMA_ERROR__ANCHOR__ARGUMENT_TYPE_MISSING = 2100002; export const CODAMA_ERROR__ANCHOR__TYPE_PATH_MISSING = 2100003; export const CODAMA_ERROR__ANCHOR__SEED_KIND_UNIMPLEMENTED = 2100004; export const CODAMA_ERROR__ANCHOR__PROGRAM_ID_KIND_UNIMPLEMENTED = 2100005; export const CODAMA_ERROR__ANCHOR__GENERIC_TYPE_MISSING = 2100006; export const CODAMA_ERROR__ANCHOR__EVENT_TYPE_MISSING = 2100007; // Dynamic-client-related errors. // Reserve error codes in the range [2500000-2500999]. export const CODAMA_ERROR__DYNAMIC_CLIENT__INSTRUCTION_NOT_FOUND = 2500000; export const CODAMA_ERROR__DYNAMIC_CLIENT__PDA_NOT_FOUND = 2500001; export const CODAMA_ERROR__DYNAMIC_CLIENT__NODE_REFERENCE_NOT_FOUND = 2500002; export const CODAMA_ERROR__DYNAMIC_CLIENT__ACCOUNT_MISSING = 2500003; export const CODAMA_ERROR__DYNAMIC_CLIENT__INVALID_ACCOUNT_ADDRESS = 2500004; export const CODAMA_ERROR__DYNAMIC_CLIENT__UNEXPECTED_ADDRESS_TYPE = 2500005; export const CODAMA_ERROR__DYNAMIC_CLIENT__CANNOT_CONVERT_TO_ADDRESS = 2500006; export const CODAMA_ERROR__DYNAMIC_CLIENT__ACCOUNT_RESOLVER_MISSING = 2500007; export const CODAMA_ERROR__DYNAMIC_CLIENT__CIRCULAR_ACCOUNT_DEPENDENCY = 2500008; export const CODAMA_ERROR__DYNAMIC_CLIENT__UNSUPPORTED_OPTIONAL_ACCOUNT_STRATEGY = 2500009; export const CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_DERIVE_PDA = 2500010; export const CODAMA_ERROR__DYNAMIC_CLIENT__ARGUMENT_MISSING = 2500011; export const CODAMA_ERROR__DYNAMIC_CLIENT__DEFAULT_VALUE_MISSING = 2500012; export const CODAMA_ERROR__DYNAMIC_CLIENT__INVALID_ARGUMENT_INPUT = 2500013; export const CODAMA_ERROR__DYNAMIC_CLIENT__UNEXPECTED_ARGUMENT_TYPE = 2500014; export const CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_ENCODE_ARGUMENT = 2500015; export const CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_EXECUTE_RESOLVER = 2500016; export const CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_VALIDATE_INPUT = 2500017; export const CODAMA_ERROR__DYNAMIC_CLIENT__UNSUPPORTED_NODE = 2500018; export const CODAMA_ERROR__DYNAMIC_CLIENT__INVARIANT_VIOLATION = 2500019; // Renderers-related errors. // Reserve error codes in the range [2800000-2800999]. export const CODAMA_ERROR__RENDERERS__UNSUPPORTED_NODE = 2800000; export const CODAMA_ERROR__RENDERERS__MISSING_DEPENDENCY_VERSIONS = 2800001; /** * A union of every Codama error code * * You might be wondering why this is not a TypeScript enum or const enum. * * One of the goals of this library is to enable people to use some or none of it without having to * bundle all of it. * * If we made the set of error codes an enum then anyone who imported it (even if to only use a * single error code) would be forced to bundle every code and its label. * * Const enums appear to solve this problem by letting the compiler inline only the codes that are * actually used. Unfortunately exporting ambient (const) enums from a library like `@codama/errors` * is not safe, for a variety of reasons covered here: https://stackoverflow.com/a/28818850 */ export type CodamaErrorCode = | typeof CODAMA_ERROR__ANCHOR__ACCOUNT_TYPE_MISSING | typeof CODAMA_ERROR__ANCHOR__ARGUMENT_TYPE_MISSING | typeof CODAMA_ERROR__ANCHOR__EVENT_TYPE_MISSING | typeof CODAMA_ERROR__ANCHOR__GENERIC_TYPE_MISSING | typeof CODAMA_ERROR__ANCHOR__PROGRAM_ID_KIND_UNIMPLEMENTED | typeof CODAMA_ERROR__ANCHOR__SEED_KIND_UNIMPLEMENTED | typeof CODAMA_ERROR__ANCHOR__TYPE_PATH_MISSING | typeof CODAMA_ERROR__ANCHOR__UNRECOGNIZED_IDL_TYPE | typeof CODAMA_ERROR__DISCRIMINATOR_FIELD_HAS_NO_DEFAULT_VALUE | typeof CODAMA_ERROR__DISCRIMINATOR_FIELD_NOT_FOUND | typeof CODAMA_ERROR__DYNAMIC_CLIENT__ACCOUNT_MISSING | typeof CODAMA_ERROR__DYNAMIC_CLIENT__ACCOUNT_RESOLVER_MISSING | typeof CODAMA_ERROR__DYNAMIC_CLIENT__ARGUMENT_MISSING | typeof CODAMA_ERROR__DYNAMIC_CLIENT__CANNOT_CONVERT_TO_ADDRESS | typeof CODAMA_ERROR__DYNAMIC_CLIENT__CIRCULAR_ACCOUNT_DEPENDENCY | typeof CODAMA_ERROR__DYNAMIC_CLIENT__DEFAULT_VALUE_MISSING | typeof CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_DERIVE_PDA | typeof CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_ENCODE_ARGUMENT | typeof CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_EXECUTE_RESOLVER | typeof CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_VALIDATE_INPUT | typeof CODAMA_ERROR__DYNAMIC_CLIENT__INSTRUCTION_NOT_FOUND | typeof CODAMA_ERROR__DYNAMIC_CLIENT__INVALID_ACCOUNT_ADDRESS | typeof CODAMA_ERROR__DYNAMIC_CLIENT__INVALID_ARGUMENT_INPUT | typeof CODAMA_ERROR__DYNAMIC_CLIENT__INVARIANT_VIOLATION | typeof CODAMA_ERROR__DYNAMIC_CLIENT__NODE_REFERENCE_NOT_FOUND | typeof CODAMA_ERROR__DYNAMIC_CLIENT__PDA_NOT_FOUND | typeof CODAMA_ERROR__DYNAMIC_CLIENT__UNEXPECTED_ADDRESS_TYPE | typeof CODAMA_ERROR__DYNAMIC_CLIENT__UNEXPECTED_ARGUMENT_TYPE | typeof CODAMA_ERROR__DYNAMIC_CLIENT__UNSUPPORTED_NODE | typeof CODAMA_ERROR__DYNAMIC_CLIENT__UNSUPPORTED_OPTIONAL_ACCOUNT_STRATEGY | typeof CODAMA_ERROR__ENUM_VARIANT_NOT_FOUND | typeof CODAMA_ERROR__LINKED_NODE_NOT_FOUND | typeof CODAMA_ERROR__NODE_FILESYSTEM_FUNCTION_UNAVAILABLE | typeof CODAMA_ERROR__RENDERERS__MISSING_DEPENDENCY_VERSIONS | typeof CODAMA_ERROR__RENDERERS__UNSUPPORTED_NODE | typeof CODAMA_ERROR__UNEXPECTED_NESTED_NODE_KIND | typeof CODAMA_ERROR__UNEXPECTED_NODE_KIND | typeof CODAMA_ERROR__UNRECOGNIZED_BYTES_ENCODING | typeof CODAMA_ERROR__UNRECOGNIZED_NODE_KIND | typeof CODAMA_ERROR__UNRECOGNIZED_NUMBER_FORMAT | typeof CODAMA_ERROR__VERSION_MISMATCH | typeof CODAMA_ERROR__VISITORS__ACCOUNT_FIELD_NOT_FOUND | typeof CODAMA_ERROR__VISITORS__CANNOT_ADD_DUPLICATED_PDA_NAMES | typeof CODAMA_ERROR__VISITORS__CANNOT_EXTEND_MISSING_VISIT_FUNCTION | typeof CODAMA_ERROR__VISITORS__CANNOT_FLATTEN_STRUCT_WITH_CONFLICTING_ATTRIBUTES | typeof CODAMA_ERROR__VISITORS__CANNOT_REMOVE_LAST_PATH_IN_NODE_STACK | typeof CODAMA_ERROR__VISITORS__CANNOT_USE_OPTIONAL_ACCOUNT_AS_PDA_SEED_VALUE | typeof CODAMA_ERROR__VISITORS__CYCLIC_DEPENDENCY_DETECTED_WHEN_RESOLVING_INSTRUCTION_DEFAULT_VALUES | typeof CODAMA_ERROR__VISITORS__FAILED_TO_VALIDATE_NODE | typeof CODAMA_ERROR__VISITORS__INSTRUCTION_ENUM_ARGUMENT_NOT_FOUND | typeof CODAMA_ERROR__VISITORS__INVALID_INSTRUCTION_DEFAULT_VALUE_DEPENDENCY | typeof CODAMA_ERROR__VISITORS__INVALID_NUMBER_WRAPPER | typeof CODAMA_ERROR__VISITORS__INVALID_PDA_SEED_VALUES | typeof CODAMA_ERROR__VISITORS__RENDER_MAP_KEY_NOT_FOUND; ================================================ FILE: packages/errors/src/context.ts ================================================ /** * Heavily inspired by @solana/errors. * @see https://github.com/anza-xyz/kit/blob/main/packages/errors */ import { AccountNode, AccountValueNode, CamelCaseString, EnumTypeNode, InstructionAccountNode, InstructionArgumentNode, InstructionNode, LinkNode, Node, NodeKind, PdaNode, PdaSeedValueNode, ProgramNode, } from '@codama/node-types'; import { CODAMA_ERROR__ANCHOR__ACCOUNT_TYPE_MISSING, CODAMA_ERROR__ANCHOR__ARGUMENT_TYPE_MISSING, CODAMA_ERROR__ANCHOR__EVENT_TYPE_MISSING, CODAMA_ERROR__ANCHOR__GENERIC_TYPE_MISSING, CODAMA_ERROR__ANCHOR__PROGRAM_ID_KIND_UNIMPLEMENTED, CODAMA_ERROR__ANCHOR__SEED_KIND_UNIMPLEMENTED, CODAMA_ERROR__ANCHOR__TYPE_PATH_MISSING, CODAMA_ERROR__ANCHOR__UNRECOGNIZED_IDL_TYPE, CODAMA_ERROR__DISCRIMINATOR_FIELD_HAS_NO_DEFAULT_VALUE, CODAMA_ERROR__DISCRIMINATOR_FIELD_NOT_FOUND, CODAMA_ERROR__DYNAMIC_CLIENT__ACCOUNT_MISSING, CODAMA_ERROR__DYNAMIC_CLIENT__ACCOUNT_RESOLVER_MISSING, CODAMA_ERROR__DYNAMIC_CLIENT__ARGUMENT_MISSING, CODAMA_ERROR__DYNAMIC_CLIENT__CANNOT_CONVERT_TO_ADDRESS, CODAMA_ERROR__DYNAMIC_CLIENT__CIRCULAR_ACCOUNT_DEPENDENCY, CODAMA_ERROR__DYNAMIC_CLIENT__DEFAULT_VALUE_MISSING, CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_DERIVE_PDA, CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_ENCODE_ARGUMENT, CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_EXECUTE_RESOLVER, CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_VALIDATE_INPUT, CODAMA_ERROR__DYNAMIC_CLIENT__INSTRUCTION_NOT_FOUND, CODAMA_ERROR__DYNAMIC_CLIENT__INVALID_ACCOUNT_ADDRESS, CODAMA_ERROR__DYNAMIC_CLIENT__INVALID_ARGUMENT_INPUT, CODAMA_ERROR__DYNAMIC_CLIENT__INVARIANT_VIOLATION, CODAMA_ERROR__DYNAMIC_CLIENT__NODE_REFERENCE_NOT_FOUND, CODAMA_ERROR__DYNAMIC_CLIENT__PDA_NOT_FOUND, CODAMA_ERROR__DYNAMIC_CLIENT__UNEXPECTED_ADDRESS_TYPE, CODAMA_ERROR__DYNAMIC_CLIENT__UNEXPECTED_ARGUMENT_TYPE, CODAMA_ERROR__DYNAMIC_CLIENT__UNSUPPORTED_NODE, CODAMA_ERROR__DYNAMIC_CLIENT__UNSUPPORTED_OPTIONAL_ACCOUNT_STRATEGY, CODAMA_ERROR__ENUM_VARIANT_NOT_FOUND, CODAMA_ERROR__LINKED_NODE_NOT_FOUND, CODAMA_ERROR__NODE_FILESYSTEM_FUNCTION_UNAVAILABLE, CODAMA_ERROR__RENDERERS__MISSING_DEPENDENCY_VERSIONS, CODAMA_ERROR__RENDERERS__UNSUPPORTED_NODE, CODAMA_ERROR__UNEXPECTED_NESTED_NODE_KIND, CODAMA_ERROR__UNEXPECTED_NODE_KIND, CODAMA_ERROR__UNRECOGNIZED_BYTES_ENCODING, CODAMA_ERROR__UNRECOGNIZED_NODE_KIND, CODAMA_ERROR__UNRECOGNIZED_NUMBER_FORMAT, CODAMA_ERROR__VERSION_MISMATCH, CODAMA_ERROR__VISITORS__ACCOUNT_FIELD_NOT_FOUND, CODAMA_ERROR__VISITORS__CANNOT_ADD_DUPLICATED_PDA_NAMES, CODAMA_ERROR__VISITORS__CANNOT_EXTEND_MISSING_VISIT_FUNCTION, CODAMA_ERROR__VISITORS__CANNOT_FLATTEN_STRUCT_WITH_CONFLICTING_ATTRIBUTES, CODAMA_ERROR__VISITORS__CANNOT_REMOVE_LAST_PATH_IN_NODE_STACK, CODAMA_ERROR__VISITORS__CANNOT_USE_OPTIONAL_ACCOUNT_AS_PDA_SEED_VALUE, CODAMA_ERROR__VISITORS__CYCLIC_DEPENDENCY_DETECTED_WHEN_RESOLVING_INSTRUCTION_DEFAULT_VALUES, CODAMA_ERROR__VISITORS__FAILED_TO_VALIDATE_NODE, CODAMA_ERROR__VISITORS__INSTRUCTION_ENUM_ARGUMENT_NOT_FOUND, CODAMA_ERROR__VISITORS__INVALID_INSTRUCTION_DEFAULT_VALUE_DEPENDENCY, CODAMA_ERROR__VISITORS__INVALID_NUMBER_WRAPPER, CODAMA_ERROR__VISITORS__INVALID_PDA_SEED_VALUES, CODAMA_ERROR__VISITORS__RENDER_MAP_KEY_NOT_FOUND, CodamaErrorCode, } from './codes'; type DefaultUnspecifiedErrorContextToUndefined = { [P in CodamaErrorCode]: P extends keyof T ? T[P] : undefined; }; /** * WARNING: * - Don't change or remove members of an error's context. */ export type CodamaErrorContext = DefaultUnspecifiedErrorContextToUndefined<{ [CODAMA_ERROR__ANCHOR__ACCOUNT_TYPE_MISSING]: { name: string; }; [CODAMA_ERROR__ANCHOR__ARGUMENT_TYPE_MISSING]: { name: string; }; [CODAMA_ERROR__ANCHOR__EVENT_TYPE_MISSING]: { name: string; }; [CODAMA_ERROR__ANCHOR__GENERIC_TYPE_MISSING]: { name: string; }; [CODAMA_ERROR__ANCHOR__PROGRAM_ID_KIND_UNIMPLEMENTED]: { kind: string; }; [CODAMA_ERROR__ANCHOR__SEED_KIND_UNIMPLEMENTED]: { kind: string; }; [CODAMA_ERROR__ANCHOR__TYPE_PATH_MISSING]: { idlType: string; path: string; }; [CODAMA_ERROR__ANCHOR__UNRECOGNIZED_IDL_TYPE]: { idlType: string; }; [CODAMA_ERROR__DISCRIMINATOR_FIELD_HAS_NO_DEFAULT_VALUE]: { field: CamelCaseString; }; [CODAMA_ERROR__DISCRIMINATOR_FIELD_NOT_FOUND]: { field: CamelCaseString; }; [CODAMA_ERROR__DYNAMIC_CLIENT__ACCOUNT_MISSING]: { accountName: CamelCaseString; instructionName: CamelCaseString; }; [CODAMA_ERROR__DYNAMIC_CLIENT__ACCOUNT_RESOLVER_MISSING]: { accountName: CamelCaseString; resolverName: CamelCaseString; }; [CODAMA_ERROR__DYNAMIC_CLIENT__ARGUMENT_MISSING]: { argumentName: CamelCaseString; instructionName: CamelCaseString; }; [CODAMA_ERROR__DYNAMIC_CLIENT__CANNOT_CONVERT_TO_ADDRESS]: { value: string; }; [CODAMA_ERROR__DYNAMIC_CLIENT__CIRCULAR_ACCOUNT_DEPENDENCY]: { chain: string; }; [CODAMA_ERROR__DYNAMIC_CLIENT__DEFAULT_VALUE_MISSING]: { argumentName: CamelCaseString; instructionName: CamelCaseString; }; [CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_DERIVE_PDA]: { accountName: CamelCaseString; }; [CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_ENCODE_ARGUMENT]: { argumentName: CamelCaseString; instructionName: CamelCaseString; }; [CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_EXECUTE_RESOLVER]: { resolverName: CamelCaseString; targetKind: NodeKind; targetName: CamelCaseString; }; [CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_VALIDATE_INPUT]: { message: string; }; [CODAMA_ERROR__DYNAMIC_CLIENT__INSTRUCTION_NOT_FOUND]: { availableIxs: string[]; instructionName: string; }; [CODAMA_ERROR__DYNAMIC_CLIENT__INVALID_ACCOUNT_ADDRESS]: { accountName: CamelCaseString; value: string; }; [CODAMA_ERROR__DYNAMIC_CLIENT__INVALID_ARGUMENT_INPUT]: { argumentName: CamelCaseString; expectedType: string; value: string; }; [CODAMA_ERROR__DYNAMIC_CLIENT__INVARIANT_VIOLATION]: { message: string; }; [CODAMA_ERROR__DYNAMIC_CLIENT__NODE_REFERENCE_NOT_FOUND]: { instructionName: CamelCaseString; referencedName: CamelCaseString; }; [CODAMA_ERROR__DYNAMIC_CLIENT__PDA_NOT_FOUND]: { available: string; pdaName: string; }; [CODAMA_ERROR__DYNAMIC_CLIENT__UNEXPECTED_ADDRESS_TYPE]: { accountName: string; actualType: string; expectedType: string; }; [CODAMA_ERROR__DYNAMIC_CLIENT__UNEXPECTED_ARGUMENT_TYPE]: { actualType: string; expectedType: string; nodeKind: NodeKind; }; [CODAMA_ERROR__DYNAMIC_CLIENT__UNSUPPORTED_NODE]: { nodeKind: NodeKind; }; [CODAMA_ERROR__DYNAMIC_CLIENT__UNSUPPORTED_OPTIONAL_ACCOUNT_STRATEGY]: { accountName: CamelCaseString; instructionName: CamelCaseString; strategy: string; }; [CODAMA_ERROR__ENUM_VARIANT_NOT_FOUND]: { enum: EnumTypeNode; enumName: CamelCaseString; variant: CamelCaseString; }; [CODAMA_ERROR__LINKED_NODE_NOT_FOUND]: { kind: LinkNode['kind']; linkNode: LinkNode; name: CamelCaseString; path: readonly Node[]; }; [CODAMA_ERROR__NODE_FILESYSTEM_FUNCTION_UNAVAILABLE]: { fsFunction: string; }; [CODAMA_ERROR__RENDERERS__MISSING_DEPENDENCY_VERSIONS]: { dependencies: readonly string[]; message: string; }; [CODAMA_ERROR__RENDERERS__UNSUPPORTED_NODE]: { kind: NodeKind; node: Node | undefined; }; [CODAMA_ERROR__UNEXPECTED_NESTED_NODE_KIND]: { expectedKinds: NodeKind[]; kind: NodeKind | null; node: Node | null | undefined; }; [CODAMA_ERROR__UNEXPECTED_NODE_KIND]: { expectedKinds: NodeKind[]; kind: NodeKind | null; node: Node | null | undefined; }; [CODAMA_ERROR__UNRECOGNIZED_BYTES_ENCODING]: { encoding: string; }; [CODAMA_ERROR__UNRECOGNIZED_NODE_KIND]: { kind: string; }; [CODAMA_ERROR__UNRECOGNIZED_NUMBER_FORMAT]: { format: string; }; [CODAMA_ERROR__VERSION_MISMATCH]: { codamaVersion: string; rootVersion: string; }; [CODAMA_ERROR__VISITORS__ACCOUNT_FIELD_NOT_FOUND]: { account: AccountNode; missingField: CamelCaseString; name: CamelCaseString; }; [CODAMA_ERROR__VISITORS__CANNOT_ADD_DUPLICATED_PDA_NAMES]: { duplicatedPdaNames: CamelCaseString[]; program: ProgramNode; programName: CamelCaseString; }; [CODAMA_ERROR__VISITORS__CANNOT_EXTEND_MISSING_VISIT_FUNCTION]: { visitFunction: string; }; [CODAMA_ERROR__VISITORS__CANNOT_FLATTEN_STRUCT_WITH_CONFLICTING_ATTRIBUTES]: { conflictingAttributes: CamelCaseString[]; }; [CODAMA_ERROR__VISITORS__CANNOT_REMOVE_LAST_PATH_IN_NODE_STACK]: { path: readonly Node[]; }; [CODAMA_ERROR__VISITORS__CANNOT_USE_OPTIONAL_ACCOUNT_AS_PDA_SEED_VALUE]: { instruction: InstructionNode; instructionAccount: InstructionAccountNode; instructionAccountName: CamelCaseString; instructionName: CamelCaseString; seed: PdaSeedValueNode; seedName: CamelCaseString; seedValueName: CamelCaseString; }; [CODAMA_ERROR__VISITORS__CYCLIC_DEPENDENCY_DETECTED_WHEN_RESOLVING_INSTRUCTION_DEFAULT_VALUES]: { cycle: (InstructionAccountNode | InstructionArgumentNode)[]; formattedCycle: string; instruction: InstructionNode; instructionName: CamelCaseString; }; [CODAMA_ERROR__VISITORS__FAILED_TO_VALIDATE_NODE]: { formattedHistogram: string; validationItems: ValidationItem[]; }; [CODAMA_ERROR__VISITORS__INSTRUCTION_ENUM_ARGUMENT_NOT_FOUND]: { argumentName: CamelCaseString; instruction: InstructionNode; instructionName: CamelCaseString; }; [CODAMA_ERROR__VISITORS__INVALID_INSTRUCTION_DEFAULT_VALUE_DEPENDENCY]: { dependency: InstructionAccountNode | InstructionArgumentNode; dependencyKind: 'instructionAccountNode' | 'instructionArgumentNode'; dependencyName: CamelCaseString; instruction: InstructionNode; instructionName: CamelCaseString; parent: InstructionAccountNode | InstructionArgumentNode; parentKind: 'instructionAccountNode' | 'instructionArgumentNode'; parentName: CamelCaseString; }; [CODAMA_ERROR__VISITORS__INVALID_NUMBER_WRAPPER]: { wrapper: string; }; [CODAMA_ERROR__VISITORS__INVALID_PDA_SEED_VALUES]: { instruction: InstructionNode; instructionName: CamelCaseString; pda: PdaNode; pdaName: CamelCaseString; }; [CODAMA_ERROR__VISITORS__RENDER_MAP_KEY_NOT_FOUND]: { key: string; }; }>; type ValidationItem = { level: 'debug' | 'error' | 'info' | 'trace' | 'warn'; message: string; node: Node; path: Node[]; }; export function decodeEncodedContext(encodedContext: string): object { const decodedUrlString = __NODEJS__ ? Buffer.from(encodedContext, 'base64').toString('utf8') : atob(encodedContext); return Object.fromEntries(new URLSearchParams(decodedUrlString).entries()); } function encodeValue(value: unknown): string { if (Array.isArray(value)) { const commaSeparatedValues = value.map(encodeValue).join('%2C%20' /* ", " */); return '%5B' /* "[" */ + commaSeparatedValues + /* "]" */ '%5D'; } else if (typeof value === 'bigint') { return `${value}n`; } else { return encodeURIComponent( String( value != null && Object.getPrototypeOf(value) === null ? // Plain objects with no protoype don't have a `toString` method. // Convert them before stringifying them. { ...(value as object) } : value, ), ); } } function encodeObjectContextEntry([key, value]: [string, unknown]): `${typeof key}=${string}` { return `${key}=${encodeValue(value)}`; } export function encodeContextObject(context: object): string { const searchParamsString = Object.entries(context).map(encodeObjectContextEntry).join('&'); return __NODEJS__ ? Buffer.from(searchParamsString, 'utf8').toString('base64') : btoa(searchParamsString); } ================================================ FILE: packages/errors/src/error.ts ================================================ /** * Heavily inspired by @solana/errors. * @see https://github.com/anza-xyz/kit/blob/main/packages/errors */ import { CodamaErrorCode } from './codes'; import { CodamaErrorContext } from './context'; import { getErrorMessage } from './message-formatter'; export function isCodamaError( e: unknown, code?: TErrorCode, ): e is CodamaError { const isCodamaError = e instanceof Error && e.name === 'CodamaError'; if (isCodamaError) { if (code !== undefined) { return (e as CodamaError).context.__code === code; } return true; } return false; } type CodamaErrorCodedContext = Readonly<{ [P in CodamaErrorCode]: (CodamaErrorContext[P] extends undefined ? object : CodamaErrorContext[P]) & { __code: P; }; }>; export class CodamaError extends Error { readonly context: CodamaErrorCodedContext[TErrorCode]; constructor( ...[code, contextAndErrorOptions]: CodamaErrorContext[TErrorCode] extends undefined ? [code: TErrorCode, errorOptions?: ErrorOptions | undefined] : [code: TErrorCode, contextAndErrorOptions: CodamaErrorContext[TErrorCode] & (ErrorOptions | undefined)] ) { let context: CodamaErrorContext[TErrorCode] | undefined; let errorOptions: ErrorOptions | undefined; if (contextAndErrorOptions) { // If the `ErrorOptions` type ever changes, update this code. const { cause, ...contextRest } = contextAndErrorOptions; if (cause) { errorOptions = { cause }; } if (Object.keys(contextRest).length > 0) { context = contextRest as CodamaErrorContext[TErrorCode]; } } const message = getErrorMessage(code, context); super(message, errorOptions); this.context = { __code: code, ...context, } as CodamaErrorCodedContext[TErrorCode]; // This is necessary so that `isCodamaError()` can identify a `CodamaError` without having // to import the class for use in an `instanceof` check. this.name = 'CodamaError'; } } ================================================ FILE: packages/errors/src/index.ts ================================================ export * from './codes'; export * from './error'; export * from './logs'; export * from './stack-trace'; ================================================ FILE: packages/errors/src/logs.ts ================================================ export function logError(message: string) { console.error(message); } export function logWarn(message: string) { console.warn(message); } export function logInfo(message: string) { console.log(message); } ================================================ FILE: packages/errors/src/message-formatter.ts ================================================ /** * Heavily inspired by @solana/errors. * @see https://github.com/anza-xyz/kit/blob/main/packages/errors */ import { CodamaErrorCode } from './codes'; import { encodeContextObject } from './context'; import { CodamaErrorMessages } from './messages'; export function getHumanReadableErrorMessage( code: TErrorCode, context: object = {}, ): string { const messageFormatString = CodamaErrorMessages[code]; const message = messageFormatString.replace(/(? variableName in context ? `${context[variableName as keyof typeof context] as string}` : substring, ); return message; } export function getErrorMessage(code: TErrorCode, context: object = {}): string { if (process.env.NODE_ENV !== 'production') { return getHumanReadableErrorMessage(code, context); } else { let decodingAdviceMessage = `Codama error #${code}; Decode this error by running \`npx @codama/errors decode -- ${code}`; if (Object.keys(context).length) { /** * DANGER: Be sure that the shell command is escaped in such a way that makes it * impossible for someone to craft malicious context values that would result in * an exploit against anyone who bindly copy/pastes it into their terminal. */ decodingAdviceMessage += ` '${encodeContextObject(context)}'`; } return `${decodingAdviceMessage}\``; } } ================================================ FILE: packages/errors/src/messages.ts ================================================ /** * Heavily inspired by @solana/errors. * @see https://github.com/anza-xyz/kit/blob/main/packages/errors */ import { CODAMA_ERROR__ANCHOR__ACCOUNT_TYPE_MISSING, CODAMA_ERROR__ANCHOR__ARGUMENT_TYPE_MISSING, CODAMA_ERROR__ANCHOR__EVENT_TYPE_MISSING, CODAMA_ERROR__ANCHOR__GENERIC_TYPE_MISSING, CODAMA_ERROR__ANCHOR__PROGRAM_ID_KIND_UNIMPLEMENTED, CODAMA_ERROR__ANCHOR__SEED_KIND_UNIMPLEMENTED, CODAMA_ERROR__ANCHOR__TYPE_PATH_MISSING, CODAMA_ERROR__ANCHOR__UNRECOGNIZED_IDL_TYPE, CODAMA_ERROR__DISCRIMINATOR_FIELD_HAS_NO_DEFAULT_VALUE, CODAMA_ERROR__DISCRIMINATOR_FIELD_NOT_FOUND, CODAMA_ERROR__DYNAMIC_CLIENT__ACCOUNT_MISSING, CODAMA_ERROR__DYNAMIC_CLIENT__ACCOUNT_RESOLVER_MISSING, CODAMA_ERROR__DYNAMIC_CLIENT__ARGUMENT_MISSING, CODAMA_ERROR__DYNAMIC_CLIENT__CANNOT_CONVERT_TO_ADDRESS, CODAMA_ERROR__DYNAMIC_CLIENT__CIRCULAR_ACCOUNT_DEPENDENCY, CODAMA_ERROR__DYNAMIC_CLIENT__DEFAULT_VALUE_MISSING, CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_DERIVE_PDA, CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_ENCODE_ARGUMENT, CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_EXECUTE_RESOLVER, CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_VALIDATE_INPUT, CODAMA_ERROR__DYNAMIC_CLIENT__INSTRUCTION_NOT_FOUND, CODAMA_ERROR__DYNAMIC_CLIENT__INVALID_ACCOUNT_ADDRESS, CODAMA_ERROR__DYNAMIC_CLIENT__INVALID_ARGUMENT_INPUT, CODAMA_ERROR__DYNAMIC_CLIENT__INVARIANT_VIOLATION, CODAMA_ERROR__DYNAMIC_CLIENT__NODE_REFERENCE_NOT_FOUND, CODAMA_ERROR__DYNAMIC_CLIENT__PDA_NOT_FOUND, CODAMA_ERROR__DYNAMIC_CLIENT__UNEXPECTED_ADDRESS_TYPE, CODAMA_ERROR__DYNAMIC_CLIENT__UNEXPECTED_ARGUMENT_TYPE, CODAMA_ERROR__DYNAMIC_CLIENT__UNSUPPORTED_NODE, CODAMA_ERROR__DYNAMIC_CLIENT__UNSUPPORTED_OPTIONAL_ACCOUNT_STRATEGY, CODAMA_ERROR__ENUM_VARIANT_NOT_FOUND, CODAMA_ERROR__LINKED_NODE_NOT_FOUND, CODAMA_ERROR__NODE_FILESYSTEM_FUNCTION_UNAVAILABLE, CODAMA_ERROR__RENDERERS__MISSING_DEPENDENCY_VERSIONS, CODAMA_ERROR__RENDERERS__UNSUPPORTED_NODE, CODAMA_ERROR__UNEXPECTED_NESTED_NODE_KIND, CODAMA_ERROR__UNEXPECTED_NODE_KIND, CODAMA_ERROR__UNRECOGNIZED_BYTES_ENCODING, CODAMA_ERROR__UNRECOGNIZED_NODE_KIND, CODAMA_ERROR__UNRECOGNIZED_NUMBER_FORMAT, CODAMA_ERROR__VERSION_MISMATCH, CODAMA_ERROR__VISITORS__ACCOUNT_FIELD_NOT_FOUND, CODAMA_ERROR__VISITORS__CANNOT_ADD_DUPLICATED_PDA_NAMES, CODAMA_ERROR__VISITORS__CANNOT_EXTEND_MISSING_VISIT_FUNCTION, CODAMA_ERROR__VISITORS__CANNOT_FLATTEN_STRUCT_WITH_CONFLICTING_ATTRIBUTES, CODAMA_ERROR__VISITORS__CANNOT_REMOVE_LAST_PATH_IN_NODE_STACK, CODAMA_ERROR__VISITORS__CANNOT_USE_OPTIONAL_ACCOUNT_AS_PDA_SEED_VALUE, CODAMA_ERROR__VISITORS__CYCLIC_DEPENDENCY_DETECTED_WHEN_RESOLVING_INSTRUCTION_DEFAULT_VALUES, CODAMA_ERROR__VISITORS__FAILED_TO_VALIDATE_NODE, CODAMA_ERROR__VISITORS__INSTRUCTION_ENUM_ARGUMENT_NOT_FOUND, CODAMA_ERROR__VISITORS__INVALID_INSTRUCTION_DEFAULT_VALUE_DEPENDENCY, CODAMA_ERROR__VISITORS__INVALID_NUMBER_WRAPPER, CODAMA_ERROR__VISITORS__INVALID_PDA_SEED_VALUES, CODAMA_ERROR__VISITORS__RENDER_MAP_KEY_NOT_FOUND, CodamaErrorCode, } from './codes'; /** * WARNING: * - Don't change the meaning of an error message. */ export const CodamaErrorMessages: Readonly<{ // This type makes this data structure exhaustive with respect to `SolanaErrorCode`. // TypeScript will fail to build this project if add an error code without a message. [P in CodamaErrorCode]: string; }> = { [CODAMA_ERROR__ANCHOR__ACCOUNT_TYPE_MISSING]: 'Account type [$name] is missing from the IDL types.', [CODAMA_ERROR__ANCHOR__ARGUMENT_TYPE_MISSING]: 'Argument name [$name] is missing from the instruction definition.', [CODAMA_ERROR__ANCHOR__EVENT_TYPE_MISSING]: 'Event type [$name] is missing from the IDL types.', [CODAMA_ERROR__ANCHOR__GENERIC_TYPE_MISSING]: 'Generic type [$name] is missing from the IDL types.', [CODAMA_ERROR__ANCHOR__PROGRAM_ID_KIND_UNIMPLEMENTED]: 'Program ID kind [$kind] is not implemented.', [CODAMA_ERROR__ANCHOR__SEED_KIND_UNIMPLEMENTED]: 'Seed kind [$kind] is not implemented.', [CODAMA_ERROR__ANCHOR__TYPE_PATH_MISSING]: 'Field type is missing for path [$path] in [$idlType].', [CODAMA_ERROR__ANCHOR__UNRECOGNIZED_IDL_TYPE]: 'Unrecognized Anchor IDL type [$idlType].', [CODAMA_ERROR__DISCRIMINATOR_FIELD_HAS_NO_DEFAULT_VALUE]: 'Discriminator field [$field] has no default value.', [CODAMA_ERROR__DISCRIMINATOR_FIELD_NOT_FOUND]: 'Could not find discriminator field [$field]', [CODAMA_ERROR__DYNAMIC_CLIENT__ACCOUNT_MISSING]: 'Missing account [$accountName] in [$instructionName] instruction.', [CODAMA_ERROR__DYNAMIC_CLIENT__ACCOUNT_RESOLVER_MISSING]: 'Resolver [$resolverName] not provided for account [$accountName].', [CODAMA_ERROR__DYNAMIC_CLIENT__ARGUMENT_MISSING]: 'Missing argument [$argumentName] in [$instructionName].', [CODAMA_ERROR__DYNAMIC_CLIENT__CANNOT_CONVERT_TO_ADDRESS]: 'Cannot convert value to Address: [$value].', [CODAMA_ERROR__DYNAMIC_CLIENT__CIRCULAR_ACCOUNT_DEPENDENCY]: 'Circular dependency detected: [$chain].', [CODAMA_ERROR__DYNAMIC_CLIENT__DEFAULT_VALUE_MISSING]: 'Default value is missing for argument [$argumentName] in [$instructionName].', [CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_DERIVE_PDA]: 'Failed to derive PDA for account [$accountName].', [CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_ENCODE_ARGUMENT]: 'Failed to encode argument [$argumentName] in [$instructionName].', [CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_EXECUTE_RESOLVER]: 'Resolver [$resolverName] threw an error while resolving [$targetKind] [$targetName].', [CODAMA_ERROR__DYNAMIC_CLIENT__FAILED_TO_VALIDATE_INPUT]: 'Failed to validate input: [$message].', [CODAMA_ERROR__DYNAMIC_CLIENT__INSTRUCTION_NOT_FOUND]: 'Instruction [$instructionName] not found in IDL. Available: [$availableIxs].', [CODAMA_ERROR__DYNAMIC_CLIENT__INVALID_ACCOUNT_ADDRESS]: 'Invalid account address [$accountName]: [$value].', [CODAMA_ERROR__DYNAMIC_CLIENT__INVALID_ARGUMENT_INPUT]: 'Invalid argument input [$argumentName]: [$value]. Expected [$expectedType].', [CODAMA_ERROR__DYNAMIC_CLIENT__INVARIANT_VIOLATION]: 'Internal invariant violation: [$message].', [CODAMA_ERROR__DYNAMIC_CLIENT__NODE_REFERENCE_NOT_FOUND]: 'Referenced node [$referencedName] not found in [$instructionName].', [CODAMA_ERROR__DYNAMIC_CLIENT__PDA_NOT_FOUND]: 'PDA [$pdaName] not found in IDL. Available: [$available].', [CODAMA_ERROR__DYNAMIC_CLIENT__UNEXPECTED_ADDRESS_TYPE]: 'Expected [$expectedType] for account [$accountName], but received [$actualType].', [CODAMA_ERROR__DYNAMIC_CLIENT__UNEXPECTED_ARGUMENT_TYPE]: 'Expected [$expectedType] for [$nodeKind], but received [$actualType].', [CODAMA_ERROR__DYNAMIC_CLIENT__UNSUPPORTED_NODE]: 'Unsupported node kind [$nodeKind].', [CODAMA_ERROR__DYNAMIC_CLIENT__UNSUPPORTED_OPTIONAL_ACCOUNT_STRATEGY]: 'Unsupported optional account strategy [$strategy] for account [$accountName] in [$instructionName].', [CODAMA_ERROR__ENUM_VARIANT_NOT_FOUND]: 'Enum variant [$variant] not found in enum type [$enumName].', [CODAMA_ERROR__LINKED_NODE_NOT_FOUND]: 'Could not find linked node [$name] from [$kind].', [CODAMA_ERROR__NODE_FILESYSTEM_FUNCTION_UNAVAILABLE]: 'Node.js filesystem function [$fsFunction] is not available in your environment.', [CODAMA_ERROR__RENDERERS__MISSING_DEPENDENCY_VERSIONS]: 'No version specified for the following dependencies: [$dependencies]. $message', [CODAMA_ERROR__RENDERERS__UNSUPPORTED_NODE]: 'Cannot render the encountered node of kind [$kind].', [CODAMA_ERROR__UNEXPECTED_NESTED_NODE_KIND]: 'Expected nested node of kind [$expectedKinds], got [$kind]', [CODAMA_ERROR__UNEXPECTED_NODE_KIND]: 'Expected node of kind [$expectedKinds], got [$kind].', [CODAMA_ERROR__UNRECOGNIZED_BYTES_ENCODING]: 'Unrecognized bytes encoding [$encoding].', [CODAMA_ERROR__UNRECOGNIZED_NODE_KIND]: 'Unrecognized node kind [$kind].', [CODAMA_ERROR__UNRECOGNIZED_NUMBER_FORMAT]: 'Unrecognized number format [$format].', [CODAMA_ERROR__VERSION_MISMATCH]: 'The provided RootNode version [$rootVersion] is not compatible with the installed Codama version [$codamaVersion].', [CODAMA_ERROR__VISITORS__ACCOUNT_FIELD_NOT_FOUND]: 'Account [$name] does not have a field named [$missingField].', [CODAMA_ERROR__VISITORS__CANNOT_ADD_DUPLICATED_PDA_NAMES]: 'Cannot add PDAs to program [$programName] because the following PDA names already exist [$duplicatedPdaNames].', [CODAMA_ERROR__VISITORS__CANNOT_EXTEND_MISSING_VISIT_FUNCTION]: 'Cannot extend visitor with function [$visitFunction] as the base visitor does not support it.', [CODAMA_ERROR__VISITORS__CANNOT_FLATTEN_STRUCT_WITH_CONFLICTING_ATTRIBUTES]: 'Cannot flatten struct since this would cause the following attributes to conflict [$conflictingAttributes].', [CODAMA_ERROR__VISITORS__CANNOT_REMOVE_LAST_PATH_IN_NODE_STACK]: 'Cannot remove the last path in the node stack.', [CODAMA_ERROR__VISITORS__CANNOT_USE_OPTIONAL_ACCOUNT_AS_PDA_SEED_VALUE]: 'Cannot use optional account [$seedValueName] as the [$seedName] PDA seed for the [$instructionAccountName] account of the [$instructionName] instruction.', [CODAMA_ERROR__VISITORS__CYCLIC_DEPENDENCY_DETECTED_WHEN_RESOLVING_INSTRUCTION_DEFAULT_VALUES]: "Circular dependency detected when resolving the accounts and arguments' default values of the [$instructionName] instruction. Got the following dependency cycle [$formattedCycle].", [CODAMA_ERROR__VISITORS__FAILED_TO_VALIDATE_NODE]: 'Failed to validate the given node [$formattedHistogram].', [CODAMA_ERROR__VISITORS__INSTRUCTION_ENUM_ARGUMENT_NOT_FOUND]: 'Could not find an enum argument named [$argumentName] for instruction [$instructionName].', [CODAMA_ERROR__VISITORS__INVALID_INSTRUCTION_DEFAULT_VALUE_DEPENDENCY]: 'Dependency [$dependencyName] of kind [$dependencyKind] is not a valid dependency of [$parentName] of kind [$parentKind] in the [$instructionName] instruction.', [CODAMA_ERROR__VISITORS__INVALID_NUMBER_WRAPPER]: 'Invalid number wrapper kind [$wrapper].', [CODAMA_ERROR__VISITORS__INVALID_PDA_SEED_VALUES]: 'Invalid seed values for PDA [$pdaName] in instruction [$instructionName].', [CODAMA_ERROR__VISITORS__RENDER_MAP_KEY_NOT_FOUND]: 'Cannot find key [$key] in RenderMap.', }; ================================================ FILE: packages/errors/src/stack-trace.ts ================================================ /** * Heavily inspired by @solana/errors. * @see https://github.com/anza-xyz/kit/blob/main/packages/errors */ export function safeCaptureStackTrace(...args: Parameters): void { if ('captureStackTrace' in Error && typeof Error.captureStackTrace === 'function') { Error.captureStackTrace(...args); } } ================================================ FILE: packages/errors/src/types/global.d.ts ================================================ declare const __BROWSER__: boolean; declare const __ESM__: boolean; declare const __NODEJS__: boolean; declare const __REACTNATIVE__: boolean; declare const __TEST__: boolean; declare const __VERSION__: string; ================================================ FILE: packages/errors/test/error.test.ts ================================================ import { expect, test } from 'vitest'; import { CODAMA_ERROR__UNEXPECTED_NODE_KIND, CODAMA_ERROR__UNRECOGNIZED_NODE_KIND, CodamaError, isCodamaError, } from '../src'; test('it exposes the Codama error context', () => { const error = new CodamaError(CODAMA_ERROR__UNRECOGNIZED_NODE_KIND, { kind: 'missingNode' }); expect(error.context.kind).toBe('missingNode'); }); test('it exposes the Codama error code', () => { const error = new CodamaError(CODAMA_ERROR__UNRECOGNIZED_NODE_KIND, { kind: 'missingNode' }); expect(error.context.__code).toBe(CODAMA_ERROR__UNRECOGNIZED_NODE_KIND); }); test('it calls the message formatter with the code and context', () => { const error = new CodamaError(CODAMA_ERROR__UNRECOGNIZED_NODE_KIND, { kind: 'missingNode' }); expect(error.message).toBe('Unrecognized node kind [missingNode].'); }); test('it exposes no cause when none is provided', () => { const error = new CodamaError(CODAMA_ERROR__UNRECOGNIZED_NODE_KIND, { kind: 'missingNode' }); expect(error.cause).toBeUndefined(); }); test('it exposes the cause when provided', () => { const cause = {} as unknown; const error = new CodamaError(CODAMA_ERROR__UNRECOGNIZED_NODE_KIND, { cause, kind: 'missingNode' }); expect(error.cause).toBe(cause); }); test('it returns `true` for an instance of `CodamaError`', () => { const error = new CodamaError(CODAMA_ERROR__UNRECOGNIZED_NODE_KIND, { kind: 'missingNode' }); expect(isCodamaError(error)).toBe(true); }); test('it returns `false` for an instance of `Error`', () => { expect(isCodamaError(new Error('bad thing'))).toBe(false); }); test('it returns `true` when the error code matches', () => { const error = new CodamaError(CODAMA_ERROR__UNRECOGNIZED_NODE_KIND, { kind: 'missingNode' }); expect(isCodamaError(error, CODAMA_ERROR__UNRECOGNIZED_NODE_KIND)).toBe(true); }); test('it returns `false` when the error code does not match', () => { const error = new CodamaError(CODAMA_ERROR__UNRECOGNIZED_NODE_KIND, { kind: 'missingNode' }); expect(isCodamaError(error, CODAMA_ERROR__UNEXPECTED_NODE_KIND)).toBe(false); }); ================================================ FILE: packages/errors/test/error.typetest.ts ================================================ import { PublicKeyTypeNode } from '@codama/node-types'; import { CodamaError, CodamaErrorCode, isCodamaError } from '../src'; import * as CodamaErrorCodeModule from '../src/codes'; import { CodamaErrorContext } from '../src/context'; const { CODAMA_ERROR__UNRECOGNIZED_NODE_KIND, CODAMA_ERROR__UNEXPECTED_NODE_KIND } = CodamaErrorCodeModule; // If this line raises a type error, you might have forgotten to add a new error to the // `CodamaErrorCode` union in `src/codes.ts`. Object.values(CodamaErrorCodeModule) satisfies CodamaErrorCode[]; const unexpectedNodeKindError = new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, { expectedKinds: ['numberTypeNode', 'stringTypeNode'], kind: 'publicKeyTypeNode', node: {} as PublicKeyTypeNode, }); { const code = unexpectedNodeKindError.context.__code; code satisfies typeof CODAMA_ERROR__UNEXPECTED_NODE_KIND; // @ts-expect-error Wrong error code. code satisfies typeof CODAMA_ERROR__UNRECOGNIZED_NODE_KIND; } { // @ts-expect-error Missing context. new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, {}); // @ts-expect-error Missing part of the context. new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, { expectedKinds: ['numberTypeNode', 'stringTypeNode'], node: {} as PublicKeyTypeNode, }); new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, { // @ts-expect-error Wrong context attribute. foo: 'bar', }); } unexpectedNodeKindError.context satisfies CodamaErrorContext[typeof CODAMA_ERROR__UNEXPECTED_NODE_KIND]; // @ts-expect-error Non existent context property. unexpectedNodeKindError.context.feePayer satisfies never; // @ts-expect-error Missing context. new CodamaError(CODAMA_ERROR__UNRECOGNIZED_NODE_KIND); // @ts-expect-error Missing context. new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND); const unknownError = null as unknown as CodamaError; if (unknownError.context.__code === CODAMA_ERROR__UNEXPECTED_NODE_KIND) { unknownError.context satisfies CodamaErrorContext[typeof CODAMA_ERROR__UNEXPECTED_NODE_KIND]; // @ts-expect-error Context belongs to another error code unknownError.context satisfies CodamaErrorContext[typeof CODAMA_ERROR__UNRECOGNIZED_NODE_KIND]; } const e = null as unknown; if (isCodamaError(e)) { e.context satisfies Readonly<{ __code: CodamaErrorCode }>; } if (isCodamaError(e, CODAMA_ERROR__UNEXPECTED_NODE_KIND)) { e.context satisfies CodamaErrorContext[typeof CODAMA_ERROR__UNEXPECTED_NODE_KIND]; // @ts-expect-error Context belongs to another error code e.context satisfies CodamaErrorContext[typeof CODAMA_ERROR__UNRECOGNIZED_NODE_KIND]; } // `CodamaErrorContext` must not contain any keys reserved by `ErrorOptions` (eg. `cause`) null as unknown as CodamaErrorContext satisfies { [Code in keyof CodamaErrorContext]: CodamaErrorContext[Code] extends undefined ? undefined : { [PP in keyof CodamaErrorContext[Code]]: PP extends keyof ErrorOptions ? never : CodamaErrorContext[Code][PP]; }; }; ================================================ FILE: packages/errors/test/types/global.d.ts ================================================ declare const __BROWSER__: boolean; declare const __ESM__: boolean; declare const __NODEJS__: boolean; declare const __REACTNATIVE__: boolean; declare const __TEST__: boolean; declare const __VERSION__: string; ================================================ FILE: packages/errors/tsconfig.declarations.json ================================================ { "compilerOptions": { "declaration": true, "declarationMap": true, "emitDeclarationOnly": true, "outDir": "./dist/types" }, "extends": "./tsconfig.json", "include": ["src/index.ts", "src/types"] } ================================================ FILE: packages/errors/tsconfig.json ================================================ { "$schema": "https://json.schemastore.org/tsconfig", "compilerOptions": { "lib": ["DOM", "ES2015", "ES2022.Error"], "resolveJsonModule": true }, "display": "@codama/errors", "extends": "../../tsconfig.json", "include": ["src", "test"] } ================================================ FILE: packages/errors/tsup.config.ts ================================================ import { defineConfig } from 'tsup'; import { getCliBuildConfig, getPackageBuildConfigs } from '../../tsup.config.base'; export default defineConfig([...getPackageBuildConfigs(), getCliBuildConfig()]); ================================================ FILE: packages/errors/vitest.config.mts ================================================ import { defineConfig } from 'vitest/config'; import { getVitestConfig } from '../../vitest.config.base.mjs'; export default defineConfig({ test: { projects: [getVitestConfig('browser'), getVitestConfig('node'), getVitestConfig('react-native')], }, }); ================================================ FILE: packages/library/.gitignore ================================================ dist/ ================================================ FILE: packages/library/.prettierignore ================================================ dist/ test/e2e/ test-ledger/ target/ CHANGELOG.md ================================================ FILE: packages/library/LICENSE ================================================ MIT License Copyright (c) 2025 Codama Copyright (c) 2024 Metaplex Foundation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: packages/library/README.md ================================================ # Codama ➤ Main Library [![npm][npm-image]][npm-url] [![npm-downloads][npm-downloads-image]][npm-url] [npm-downloads-image]: https://img.shields.io/npm/dm/codama.svg?style=flat [npm-image]: https://img.shields.io/npm/v/codama.svg?style=flat&label=%40codama%2Fnodes [npm-url]: https://www.npmjs.com/package/codama This package is the main library for Codama. It re-exports most of the other packages in the Codama monorepo and offers a `Codama` type with a few helpers to help bind everything together. ## Installation ```sh pnpm install codama ``` ## Packages included This package includes the following packages. Note that some of them also re-export other packages. - [`@codama/errors`](../errors) - [`@codama/nodes`](../nodes) - [`@codama/node-types`](../node-types) - [`@codama/validators`](../validators) - [`@codama/visitors`](../visitors) - [`@codama/visitor-core`](../visitor-core) ## The Codama helper Additionally, this package offers a `Codama` type and a few helper functions to help you work with Codama IDLs. ### `Codama` The `Codama` interface wraps a `RootNode` and offers some helper methods to work with it. ```ts export interface Codama { accept(visitor: Visitor): T; clone(): Codama; getJson(): string; getRoot(): RootNode; update(visitor: Visitor): void; } ``` The `accept` function allows us to visit the wrapped `RootNode` using the provided visitor. ```ts // Log the Codama IDL in the console. codama.accept(consoleLogVisitor(getDebugStringVisitor({ indent: true }))); ``` The `update` function also accepts a visitor, but it uses the return value of that visitor to update the wrapped `RootNode`. This means that, given a `RootNode`, the provided visitor should also return a `RootNode`. An error will be thrown otherwise. ```ts // Delete account nodes named "mint". codama.update(deleteNodesVisitor(['[accountNode]mint'])); // Transform all number nodes into u64 number nodes. codama.update( bottomUpTransformerVisitor([ { select: '[numberTypeNode]', transform: () => numberTypeNode(u64), }, ]), ); ``` Other helper functions include: - `clone()`: Creates a new instance of the `Codama` interface with a deep copy of the wrapped `RootNode`. - `getJson()`: Returns the JSON representation of the Codama IDL. - `getRoot()`: Returns the wrapped `RootNode`. ```ts const clonedCodama = codama.clone(); const jsonIdl = codama.getJson(); const rootNode = codama.getRoot(); ``` ### `createFromRoot(rootNode)` The `createFromRoot` function creates a new instance of the `Codama` interface from a `RootNode`. ```ts const codama = createFromRoot(rootNode(programNode({ ... }))); ``` ### `createFromJson(jsonIdl)` The `createFromJson` function creates a new instance of the `Codama` interface from a JSON representation of a `RootNode`. ```ts const json: string = fs.readFileSync('path/to/codamaIdl.json', 'utf-8'); const codama = createFromJson(json); ``` ================================================ FILE: packages/library/bin/cli.cjs ================================================ #!/usr/bin/env -S node const run = require('../dist/cli.cjs').run; run(process.argv); ================================================ FILE: packages/library/package.json ================================================ { "name": "codama", "version": "1.6.0", "description": "A Solana framework for building standardised programs", "exports": { "types": "./dist/types/index.d.ts", "react-native": "./dist/index.react-native.mjs", "browser": { "import": "./dist/index.browser.mjs", "require": "./dist/index.browser.cjs" }, "node": { "import": "./dist/index.node.mjs", "require": "./dist/index.node.cjs" } }, "browser": { "./dist/index.node.cjs": "./dist/index.browser.cjs", "./dist/index.node.mjs": "./dist/index.browser.mjs" }, "jsdelivr": "./dist/index.production.min.js", "umd": "./dist/index.production.min.js", "unpkg": "./dist/index.production.min.js", "main": "./dist/index.node.cjs", "module": "./dist/index.node.mjs", "react-native": "./dist/index.react-native.mjs", "types": "./dist/types/index.d.ts", "type": "commonjs", "bin": "./bin/cli.cjs", "files": [ "./bin", "./dist/types", "./dist/cli.*", "./dist/index.*" ], "sideEffects": false, "keywords": [ "solana", "framework", "standard", "specifications", "code generation" ], "scripts": { "build": "rimraf dist && tsup && tsc -p ./tsconfig.declarations.json", "dev": "vitest --project node", "lint": "eslint . && prettier --check .", "lint:fix": "eslint --fix . && prettier --write .", "test": "pnpm test:types && pnpm test:treeshakability && pnpm test:unit", "test:treeshakability": "for file in dist/index.*.mjs; do agadoo $file; done", "test:types": "tsc --noEmit", "test:unit": "vitest run" }, "dependencies": { "@codama/cli": "workspace:*", "@codama/errors": "workspace:*", "@codama/nodes": "workspace:*", "@codama/validators": "workspace:*", "@codama/visitors": "workspace:*" }, "license": "MIT", "repository": { "type": "git", "url": "https://github.com/codama-idl/codama" }, "bugs": { "url": "http://github.com/codama-idl/codama/issues" }, "browserslist": [ "supports bigint and not dead", "maintained node versions" ] } ================================================ FILE: packages/library/src/cli/index.ts ================================================ import { createProgram, runProgram } from '@codama/cli'; const program = createProgram(); export async function run(argv: readonly string[]) { await runProgram(program, argv); } ================================================ FILE: packages/library/src/codama.ts ================================================ import { CODAMA_ERROR__VERSION_MISMATCH } from '@codama/errors'; import { CodamaError } from '@codama/errors'; import { assertIsNode, CodamaVersion, Node, RootNode } from '@codama/nodes'; import { visit, Visitor } from '@codama/visitors'; export interface Codama { accept(visitor: Visitor): T; clone(): Codama; getJson(): string; getRoot(): RootNode; update(visitor: Visitor): void; } export function createFromRoot(root: RootNode): Codama { let currentRoot = root; validateCodamaVersion(currentRoot.version); return { accept(visitor: Visitor): T { return visit(currentRoot, visitor); }, clone(): Codama { return createFromRoot({ ...currentRoot }); }, getJson(): string { return JSON.stringify(currentRoot); }, getRoot(): RootNode { return currentRoot; }, update(visitor: Visitor): void { const newRoot = visit(currentRoot, visitor); assertIsNode(newRoot, 'rootNode'); currentRoot = newRoot; }, }; } export function createFromJson(json: string): Codama { return createFromRoot(JSON.parse(json) as RootNode); } export function validateCodamaVersion(rootVersion: CodamaVersion): void { const codamaVersion = __VERSION__; if (rootVersion === codamaVersion) return; const [rootMajor, rootMinor] = rootVersion.split('.').map(Number); const [CodamaMajor, CodamaMinor] = codamaVersion.split('.').map(Number); const isZeroMajor = rootMajor === 0 && CodamaMajor === 0; if (isZeroMajor && rootMinor === CodamaMinor) return; if (rootMajor === CodamaMajor) return; throw new CodamaError(CODAMA_ERROR__VERSION_MISMATCH, { codamaVersion, rootVersion }); } ================================================ FILE: packages/library/src/index.ts ================================================ export * from '@codama/errors'; export * from '@codama/nodes'; export * from '@codama/validators'; export * from '@codama/visitors'; export * from './codama'; ================================================ FILE: packages/library/src/types/global.d.ts ================================================ declare const __BROWSER__: boolean; declare const __ESM__: boolean; declare const __NODEJS__: boolean; declare const __REACTNATIVE__: boolean; declare const __TEST__: boolean; declare const __VERSION__: string; ================================================ FILE: packages/library/test/index.test.ts ================================================ import { expect, test } from 'vitest'; import { createFromRoot, identityVisitor, programNode, rootNode, rootNodeVisitor, voidVisitor } from '../src'; test('it exports node helpers', () => { expect(typeof rootNode).toBe('function'); }); test('it exports visitors', () => { expect(typeof identityVisitor).toBe('function'); }); test('it accepts visitors', () => { const codama = createFromRoot(rootNode(programNode({ name: 'myProgram', publicKey: '1111' }))); const visitor = voidVisitor({ keys: ['rootNode'] }); const result = codama.accept(visitor) satisfies void; expect(typeof result).toBe('undefined'); }); test('it updates the root node returned by visitors', () => { const codama = createFromRoot(rootNode(programNode({ name: 'myProgram', publicKey: '1111' }))); const visitor = rootNodeVisitor(node => rootNode(programNode({ ...node.program, name: 'myTransformedProgram' }))); codama.update(visitor) satisfies void; expect(codama.getRoot()).toEqual(rootNode(programNode({ name: 'myTransformedProgram', publicKey: '1111' }))); }); ================================================ FILE: packages/library/tsconfig.declarations.json ================================================ { "compilerOptions": { "declaration": true, "declarationMap": true, "emitDeclarationOnly": true, "outDir": "./dist/types" }, "extends": "./tsconfig.json", "include": ["src/index.ts", "src/types"] } ================================================ FILE: packages/library/tsconfig.json ================================================ { "$schema": "https://json.schemastore.org/tsconfig", "compilerOptions": { "lib": ["DOM", "ES2015", "ES2022.Error"], "resolveJsonModule": true }, "display": "codama", "extends": "../../tsconfig.json", "include": ["src", "test"] } ================================================ FILE: packages/library/tsup.config.ts ================================================ import { defineConfig } from 'tsup'; import { getBuildConfig, getCliBuildConfig, getPackageBuildConfigs } from '../../tsup.config.base'; export default defineConfig([ ...getPackageBuildConfigs(), getBuildConfig({ format: 'iife', platform: 'browser' }), getCliBuildConfig(), ]); ================================================ FILE: packages/library/vitest.config.mts ================================================ import { defineConfig } from 'vitest/config'; import { getVitestConfig } from '../../vitest.config.base.mjs'; export default defineConfig({ test: { projects: [getVitestConfig('browser'), getVitestConfig('node'), getVitestConfig('react-native')], }, }); ================================================ FILE: packages/node-types/.gitignore ================================================ dist/ ================================================ FILE: packages/node-types/.prettierignore ================================================ dist/ test/e2e/ test-ledger/ target/ CHANGELOG.md ================================================ FILE: packages/node-types/LICENSE ================================================ MIT License Copyright (c) 2025 Codama Copyright (c) 2024 Metaplex Foundation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: packages/node-types/README.md ================================================ # Codama ➤ Node Types [![npm][npm-image]][npm-url] [![npm-downloads][npm-downloads-image]][npm-url] [npm-downloads-image]: https://img.shields.io/npm/dm/@codama/node-types.svg?style=flat [npm-image]: https://img.shields.io/npm/v/@codama/node-types.svg?style=flat&label=%40codama%2Fnode-types [npm-url]: https://www.npmjs.com/package/@codama/node-types This package is the type-only version of the `@codama/nodes` package. Check out the [nodes documentation](../nodes) for more information. ## Installation ```sh pnpm install @codama/node-types ``` > [!NOTE] > This package is included in the [`@codama/nodes`](../nodes) package and in the main [`codama`](../library) library. Meaning, you already have access to its content if you are installing Codama in one of these ways. > > ```sh > pnpm install @codama/nodes > pnpm install codama > ``` ================================================ FILE: packages/node-types/package.json ================================================ { "name": "@codama/node-types", "version": "1.6.0", "description": "Node specifications for the Codama standard", "exports": { "types": "./dist/types/index.d.ts", "react-native": "./dist/index.react-native.mjs", "browser": { "import": "./dist/index.browser.mjs", "require": "./dist/index.browser.cjs" }, "node": { "import": "./dist/index.node.mjs", "require": "./dist/index.node.cjs" } }, "browser": { "./dist/index.node.cjs": "./dist/index.browser.cjs", "./dist/index.node.mjs": "./dist/index.browser.mjs" }, "main": "./dist/index.node.cjs", "module": "./dist/index.node.mjs", "react-native": "./dist/index.react-native.mjs", "types": "./dist/types/index.d.ts", "type": "commonjs", "files": [ "./dist/types", "./dist/index.*" ], "sideEffects": false, "keywords": [ "solana", "framework", "standard", "specifications" ], "scripts": { "build": "rimraf dist && tsup && tsc -p ./tsconfig.declarations.json", "lint": "eslint . && prettier --check .", "lint:fix": "eslint --fix . && prettier --write .", "test": "pnpm test:types && pnpm test:treeshakability", "test:treeshakability": "for file in dist/index.*.mjs; do agadoo $file; done", "test:types": "tsc --noEmit" }, "license": "MIT", "repository": { "type": "git", "url": "https://github.com/codama-idl/codama" }, "bugs": { "url": "http://github.com/codama-idl/codama/issues" }, "browserslist": [ "supports bigint and not dead", "maintained node versions" ] } ================================================ FILE: packages/node-types/src/AccountNode.ts ================================================ import type { DiscriminatorNode } from './discriminatorNodes'; import type { PdaLinkNode } from './linkNodes'; import type { CamelCaseString, Docs } from './shared'; import type { NestedTypeNode, StructTypeNode } from './typeNodes'; export interface AccountNode< TData extends NestedTypeNode = NestedTypeNode, TPda extends PdaLinkNode | undefined = PdaLinkNode | undefined, TDiscriminators extends DiscriminatorNode[] | undefined = DiscriminatorNode[] | undefined, > { readonly kind: 'accountNode'; // Data. readonly name: CamelCaseString; readonly size?: number | null; readonly docs?: Docs; // Children. readonly data: TData; readonly pda?: TPda; readonly discriminators?: TDiscriminators; } ================================================ FILE: packages/node-types/src/DefinedTypeNode.ts ================================================ import type { CamelCaseString, Docs } from './shared'; import type { TypeNode } from './typeNodes/TypeNode'; export interface DefinedTypeNode { readonly kind: 'definedTypeNode'; // Data. readonly name: CamelCaseString; readonly docs?: Docs; // Children. readonly type: TType; } ================================================ FILE: packages/node-types/src/ErrorNode.ts ================================================ import type { CamelCaseString, Docs } from './shared'; export interface ErrorNode { readonly kind: 'errorNode'; // Data. readonly name: CamelCaseString; readonly code: number; readonly message: string; readonly docs?: Docs; } ================================================ FILE: packages/node-types/src/EventNode.ts ================================================ import type { DiscriminatorNode } from './discriminatorNodes'; import type { CamelCaseString, Docs } from './shared'; import type { TypeNode } from './typeNodes'; export interface EventNode< TData extends TypeNode = TypeNode, TDiscriminators extends DiscriminatorNode[] | undefined = DiscriminatorNode[] | undefined, > { readonly kind: 'eventNode'; // Data. readonly name: CamelCaseString; readonly docs?: Docs; // Children. readonly data: TData; readonly discriminators?: TDiscriminators; } ================================================ FILE: packages/node-types/src/InstructionAccountNode.ts ================================================ import type { InstructionInputValueNode } from './contextualValueNodes'; import type { CamelCaseString, Docs } from './shared'; export interface InstructionAccountNode< TDefaultValue extends InstructionInputValueNode | undefined = InstructionInputValueNode | undefined, > { readonly kind: 'instructionAccountNode'; // Data. readonly name: CamelCaseString; readonly isWritable: boolean; readonly isSigner: boolean | 'either'; readonly isOptional?: boolean; readonly docs?: Docs; // Children. readonly defaultValue?: TDefaultValue; } ================================================ FILE: packages/node-types/src/InstructionArgumentNode.ts ================================================ import type { InstructionInputValueNode } from './contextualValueNodes'; import type { CamelCaseString, Docs } from './shared'; import type { TypeNode } from './typeNodes'; export interface InstructionArgumentNode< TDefaultValue extends InstructionInputValueNode | undefined = InstructionInputValueNode | undefined, > { readonly kind: 'instructionArgumentNode'; // Data. readonly name: CamelCaseString; readonly defaultValueStrategy?: 'omitted' | 'optional'; readonly docs?: Docs; // Children. readonly type: TypeNode; readonly defaultValue?: TDefaultValue; } ================================================ FILE: packages/node-types/src/InstructionByteDeltaNode.ts ================================================ import type { ArgumentValueNode, ResolverValueNode } from './contextualValueNodes'; import type { AccountLinkNode } from './linkNodes'; import type { NumberValueNode } from './valueNodes'; type InstructionByteDeltaNodeValue = AccountLinkNode | ArgumentValueNode | NumberValueNode | ResolverValueNode; export interface InstructionByteDeltaNode< TValue extends InstructionByteDeltaNodeValue = InstructionByteDeltaNodeValue, > { readonly kind: 'instructionByteDeltaNode'; // Data. readonly withHeader: boolean; readonly subtract?: boolean; // Children. readonly value: TValue; } ================================================ FILE: packages/node-types/src/InstructionNode.ts ================================================ import type { DiscriminatorNode } from './discriminatorNodes'; import type { InstructionAccountNode } from './InstructionAccountNode'; import type { InstructionArgumentNode } from './InstructionArgumentNode'; import type { InstructionByteDeltaNode } from './InstructionByteDeltaNode'; import type { InstructionRemainingAccountsNode } from './InstructionRemainingAccountsNode'; import type { InstructionStatusNode } from './InstructionStatusNode'; import type { CamelCaseString, Docs } from './shared'; type SubInstructionNode = InstructionNode; export type OptionalAccountStrategy = 'omitted' | 'programId'; export interface InstructionNode< TAccounts extends InstructionAccountNode[] = InstructionAccountNode[], TArguments extends InstructionArgumentNode[] = InstructionArgumentNode[], TExtraArguments extends InstructionArgumentNode[] | undefined = InstructionArgumentNode[] | undefined, TRemainingAccounts extends InstructionRemainingAccountsNode[] | undefined = | InstructionRemainingAccountsNode[] | undefined, TByteDeltas extends InstructionByteDeltaNode[] | undefined = InstructionByteDeltaNode[] | undefined, TDiscriminators extends DiscriminatorNode[] | undefined = DiscriminatorNode[] | undefined, TSubInstructions extends SubInstructionNode[] | undefined = SubInstructionNode[] | undefined, > { readonly kind: 'instructionNode'; // Data. readonly name: CamelCaseString; readonly docs?: Docs; readonly optionalAccountStrategy?: OptionalAccountStrategy; // Children. readonly accounts: TAccounts; readonly arguments: TArguments; readonly extraArguments?: TExtraArguments; readonly remainingAccounts?: TRemainingAccounts; readonly byteDeltas?: TByteDeltas; readonly discriminators?: TDiscriminators; readonly status?: InstructionStatusNode; readonly subInstructions?: TSubInstructions; } ================================================ FILE: packages/node-types/src/InstructionRemainingAccountsNode.ts ================================================ import type { ArgumentValueNode, ResolverValueNode } from './contextualValueNodes'; import type { Docs } from './shared'; export interface InstructionRemainingAccountsNode< TValue extends ArgumentValueNode | ResolverValueNode = ArgumentValueNode | ResolverValueNode, > { readonly kind: 'instructionRemainingAccountsNode'; // Data. readonly isOptional?: boolean; readonly isSigner?: boolean | 'either'; readonly isWritable?: boolean; readonly docs?: Docs; // Children. readonly value: TValue; } ================================================ FILE: packages/node-types/src/InstructionStatusNode.ts ================================================ import type { InstructionLifecycle } from './shared'; export interface InstructionStatusNode { readonly kind: 'instructionStatusNode'; // Data. readonly lifecycle: InstructionLifecycle; readonly message?: string; } ================================================ FILE: packages/node-types/src/Node.ts ================================================ import type { AccountNode } from './AccountNode'; import type { RegisteredContextualValueNode } from './contextualValueNodes/ContextualValueNode'; import type { RegisteredCountNode } from './countNodes/CountNode'; import type { DefinedTypeNode } from './DefinedTypeNode'; import type { RegisteredDiscriminatorNode } from './discriminatorNodes/DiscriminatorNode'; import type { ErrorNode } from './ErrorNode'; import type { EventNode } from './EventNode'; import type { InstructionAccountNode } from './InstructionAccountNode'; import type { InstructionArgumentNode } from './InstructionArgumentNode'; import type { InstructionByteDeltaNode } from './InstructionByteDeltaNode'; import type { InstructionNode } from './InstructionNode'; import type { InstructionRemainingAccountsNode } from './InstructionRemainingAccountsNode'; import type { InstructionStatusNode } from './InstructionStatusNode'; import type { RegisteredLinkNode } from './linkNodes/LinkNode'; import type { PdaNode } from './PdaNode'; import type { RegisteredPdaSeedNode } from './pdaSeedNodes/PdaSeedNode'; import type { ProgramNode } from './ProgramNode'; import type { RootNode } from './RootNode'; import type { RegisteredTypeNode } from './typeNodes/TypeNode'; import type { RegisteredValueNode } from './valueNodes/ValueNode'; // Node Registration. export type NodeKind = Node['kind']; export type Node = | AccountNode | DefinedTypeNode | ErrorNode | EventNode | InstructionAccountNode | InstructionArgumentNode | InstructionByteDeltaNode | InstructionNode | InstructionRemainingAccountsNode | InstructionStatusNode | PdaNode | ProgramNode | RegisteredContextualValueNode | RegisteredCountNode | RegisteredDiscriminatorNode | RegisteredLinkNode | RegisteredPdaSeedNode | RegisteredTypeNode | RegisteredValueNode | RootNode; // Node Helpers. export type GetNodeFromKind = Extract; ================================================ FILE: packages/node-types/src/PdaNode.ts ================================================ import type { PdaSeedNode } from './pdaSeedNodes'; import type { CamelCaseString, Docs } from './shared'; export interface PdaNode { readonly kind: 'pdaNode'; // Data. readonly name: CamelCaseString; readonly docs?: Docs; readonly programId?: string; // Children. readonly seeds: TSeeds; } ================================================ FILE: packages/node-types/src/ProgramNode.ts ================================================ import type { AccountNode } from './AccountNode'; import type { DefinedTypeNode } from './DefinedTypeNode'; import type { ErrorNode } from './ErrorNode'; import type { EventNode } from './EventNode'; import type { InstructionNode } from './InstructionNode'; import type { PdaNode } from './PdaNode'; import type { CamelCaseString, Docs, ProgramVersion } from './shared'; export interface ProgramNode< TPdas extends PdaNode[] = PdaNode[], TAccounts extends AccountNode[] = AccountNode[], TInstructions extends InstructionNode[] = InstructionNode[], TDefinedTypes extends DefinedTypeNode[] = DefinedTypeNode[], TErrors extends ErrorNode[] = ErrorNode[], TEvents extends EventNode[] = EventNode[], > { readonly kind: 'programNode'; // Data. readonly name: CamelCaseString; readonly publicKey: string; readonly version: ProgramVersion; readonly origin?: 'anchor' | 'shank'; readonly docs?: Docs; // Children. readonly accounts: TAccounts; readonly instructions: TInstructions; readonly definedTypes: TDefinedTypes; readonly pdas: TPdas; readonly events: TEvents; readonly errors: TErrors; } ================================================ FILE: packages/node-types/src/RootNode.ts ================================================ import type { ProgramNode } from './ProgramNode'; import type { CodamaVersion } from './shared'; export interface RootNode< TProgram extends ProgramNode = ProgramNode, TAdditionalPrograms extends ProgramNode[] = ProgramNode[], > { readonly kind: 'rootNode'; // Data. readonly standard: 'codama'; readonly version: CodamaVersion; // Children. readonly program: TProgram; readonly additionalPrograms: TAdditionalPrograms; } ================================================ FILE: packages/node-types/src/contextualValueNodes/AccountBumpValueNode.ts ================================================ import type { CamelCaseString } from '../shared'; export interface AccountBumpValueNode { readonly kind: 'accountBumpValueNode'; // Data. readonly name: CamelCaseString; } ================================================ FILE: packages/node-types/src/contextualValueNodes/AccountValueNode.ts ================================================ import type { CamelCaseString } from '../shared'; export interface AccountValueNode { readonly kind: 'accountValueNode'; // Data. readonly name: CamelCaseString; } ================================================ FILE: packages/node-types/src/contextualValueNodes/ArgumentValueNode.ts ================================================ import type { CamelCaseString } from '../shared'; export interface ArgumentValueNode { readonly kind: 'argumentValueNode'; // Data. readonly name: CamelCaseString; } ================================================ FILE: packages/node-types/src/contextualValueNodes/ConditionalValueNode.ts ================================================ import type { ValueNode } from '../valueNodes'; import type { AccountValueNode } from './AccountValueNode'; import type { ArgumentValueNode } from './ArgumentValueNode'; import type { InstructionInputValueNode } from './ContextualValueNode'; import type { ResolverValueNode } from './ResolverValueNode'; type ConditionNode = AccountValueNode | ArgumentValueNode | ResolverValueNode; export interface ConditionalValueNode< TCondition extends ConditionNode = ConditionNode, TValue extends ValueNode | undefined = ValueNode | undefined, TIfTrue extends InstructionInputValueNode | undefined = InstructionInputValueNode | undefined, TIfFalse extends InstructionInputValueNode | undefined = InstructionInputValueNode | undefined, > { readonly kind: 'conditionalValueNode'; // Children. readonly condition: TCondition; readonly value?: TValue; readonly ifTrue?: TIfTrue; readonly ifFalse?: TIfFalse; } ================================================ FILE: packages/node-types/src/contextualValueNodes/ContextualValueNode.ts ================================================ import type { ProgramLinkNode } from '../linkNodes/ProgramLinkNode'; import type { ValueNode } from '../valueNodes/ValueNode'; import type { AccountBumpValueNode } from './AccountBumpValueNode'; import type { AccountValueNode } from './AccountValueNode'; import type { ArgumentValueNode } from './ArgumentValueNode'; import type { ConditionalValueNode } from './ConditionalValueNode'; import type { IdentityValueNode } from './IdentityValueNode'; import type { PayerValueNode } from './PayerValueNode'; import type { PdaSeedValueNode } from './PdaSeedValueNode'; import type { PdaValueNode } from './PdaValueNode'; import type { ProgramIdValueNode } from './ProgramIdValueNode'; import type { ResolverValueNode } from './ResolverValueNode'; // Standalone Contextual Value Node Registration. export type StandaloneContextualValueNode = | AccountBumpValueNode | AccountValueNode | ArgumentValueNode | ConditionalValueNode | IdentityValueNode | PayerValueNode | PdaValueNode | ProgramIdValueNode | ResolverValueNode; // Contextual Value Node Registration. export type RegisteredContextualValueNode = PdaSeedValueNode | StandaloneContextualValueNode; // Contextual Value Node Helpers. export type ContextualValueNode = StandaloneContextualValueNode; export type InstructionInputValueNode = ContextualValueNode | ProgramLinkNode | ValueNode; ================================================ FILE: packages/node-types/src/contextualValueNodes/IdentityValueNode.ts ================================================ export interface IdentityValueNode { readonly kind: 'identityValueNode'; } ================================================ FILE: packages/node-types/src/contextualValueNodes/PayerValueNode.ts ================================================ export interface PayerValueNode { readonly kind: 'payerValueNode'; } ================================================ FILE: packages/node-types/src/contextualValueNodes/PdaSeedValueNode.ts ================================================ import type { CamelCaseString } from '../shared'; import type { ValueNode } from '../valueNodes'; import type { AccountValueNode } from './AccountValueNode'; import type { ArgumentValueNode } from './ArgumentValueNode'; export interface PdaSeedValueNode< TValue extends AccountValueNode | ArgumentValueNode | ValueNode = AccountValueNode | ArgumentValueNode | ValueNode, > { readonly kind: 'pdaSeedValueNode'; // Data. readonly name: CamelCaseString; // Children. readonly value: TValue; } ================================================ FILE: packages/node-types/src/contextualValueNodes/PdaValueNode.ts ================================================ import type { PdaLinkNode } from '../linkNodes'; import type { PdaNode } from '../PdaNode'; import type { AccountValueNode } from './AccountValueNode'; import type { ArgumentValueNode } from './ArgumentValueNode'; import type { PdaSeedValueNode } from './PdaSeedValueNode'; export interface PdaValueNode< TSeeds extends PdaSeedValueNode[] = PdaSeedValueNode[], TProgram extends AccountValueNode | ArgumentValueNode | undefined = | AccountValueNode | ArgumentValueNode | undefined, > { readonly kind: 'pdaValueNode'; // Children. readonly pda: PdaLinkNode | PdaNode; readonly seeds: TSeeds; readonly programId?: TProgram; } ================================================ FILE: packages/node-types/src/contextualValueNodes/ProgramIdValueNode.ts ================================================ export interface ProgramIdValueNode { readonly kind: 'programIdValueNode'; } ================================================ FILE: packages/node-types/src/contextualValueNodes/ResolverValueNode.ts ================================================ import type { CamelCaseString, Docs } from '../shared'; import type { AccountValueNode } from './AccountValueNode'; import type { ArgumentValueNode } from './ArgumentValueNode'; export interface ResolverValueNode< TDependsOn extends (AccountValueNode | ArgumentValueNode)[] = (AccountValueNode | ArgumentValueNode)[], > { readonly kind: 'resolverValueNode'; // Data. readonly name: CamelCaseString; readonly docs?: Docs; // Children. readonly dependsOn?: TDependsOn; } ================================================ FILE: packages/node-types/src/contextualValueNodes/index.ts ================================================ export * from './AccountBumpValueNode'; export * from './AccountValueNode'; export * from './ArgumentValueNode'; export * from './ConditionalValueNode'; export * from './ContextualValueNode'; export * from './IdentityValueNode'; export * from './PayerValueNode'; export * from './PdaSeedValueNode'; export * from './PdaValueNode'; export * from './ProgramIdValueNode'; export * from './ResolverValueNode'; ================================================ FILE: packages/node-types/src/countNodes/CountNode.ts ================================================ import type { FixedCountNode } from './FixedCountNode'; import type { PrefixedCountNode } from './PrefixedCountNode'; import type { RemainderCountNode } from './RemainderCountNode'; // Count Node Registration. export type RegisteredCountNode = FixedCountNode | PrefixedCountNode | RemainderCountNode; // Count Node Helpers. export type CountNode = RegisteredCountNode; ================================================ FILE: packages/node-types/src/countNodes/FixedCountNode.ts ================================================ export interface FixedCountNode { readonly kind: 'fixedCountNode'; // Data. readonly value: number; } ================================================ FILE: packages/node-types/src/countNodes/PrefixedCountNode.ts ================================================ import type { NestedTypeNode, NumberTypeNode } from '../typeNodes'; export interface PrefixedCountNode = NestedTypeNode> { readonly kind: 'prefixedCountNode'; // Children. readonly prefix: TPrefix; } ================================================ FILE: packages/node-types/src/countNodes/RemainderCountNode.ts ================================================ export interface RemainderCountNode { readonly kind: 'remainderCountNode'; } ================================================ FILE: packages/node-types/src/countNodes/index.ts ================================================ export * from './CountNode'; export * from './FixedCountNode'; export * from './PrefixedCountNode'; export * from './RemainderCountNode'; ================================================ FILE: packages/node-types/src/discriminatorNodes/ConstantDiscriminatorNode.ts ================================================ import type { ConstantValueNode } from '../valueNodes'; export interface ConstantDiscriminatorNode { readonly kind: 'constantDiscriminatorNode'; // Data. readonly offset: number; // Children. readonly constant: TConstant; } ================================================ FILE: packages/node-types/src/discriminatorNodes/DiscriminatorNode.ts ================================================ import type { ConstantDiscriminatorNode } from './ConstantDiscriminatorNode'; import type { FieldDiscriminatorNode } from './FieldDiscriminatorNode'; import type { SizeDiscriminatorNode } from './SizeDiscriminatorNode'; // Discriminator Node Registration. export type RegisteredDiscriminatorNode = ConstantDiscriminatorNode | FieldDiscriminatorNode | SizeDiscriminatorNode; // Discriminator Node Helpers. export type DiscriminatorNode = RegisteredDiscriminatorNode; ================================================ FILE: packages/node-types/src/discriminatorNodes/FieldDiscriminatorNode.ts ================================================ import type { CamelCaseString } from '../shared'; export interface FieldDiscriminatorNode { readonly kind: 'fieldDiscriminatorNode'; // Data. readonly name: CamelCaseString; readonly offset: number; } ================================================ FILE: packages/node-types/src/discriminatorNodes/SizeDiscriminatorNode.ts ================================================ export interface SizeDiscriminatorNode { readonly kind: 'sizeDiscriminatorNode'; // Data. readonly size: number; } ================================================ FILE: packages/node-types/src/discriminatorNodes/index.ts ================================================ export * from './ConstantDiscriminatorNode'; export * from './DiscriminatorNode'; export * from './FieldDiscriminatorNode'; export * from './SizeDiscriminatorNode'; ================================================ FILE: packages/node-types/src/index.ts ================================================ export * from './AccountNode'; export * from './DefinedTypeNode'; export * from './ErrorNode'; export * from './EventNode'; export * from './InstructionAccountNode'; export * from './InstructionArgumentNode'; export * from './InstructionByteDeltaNode'; export * from './InstructionNode'; export * from './InstructionRemainingAccountsNode'; export * from './InstructionStatusNode'; export * from './Node'; export * from './PdaNode'; export * from './ProgramNode'; export * from './RootNode'; export * from './contextualValueNodes'; export * from './countNodes'; export * from './discriminatorNodes'; export * from './linkNodes'; export * from './pdaSeedNodes'; export * from './shared'; export * from './typeNodes'; export * from './valueNodes'; ================================================ FILE: packages/node-types/src/linkNodes/AccountLinkNode.ts ================================================ import type { CamelCaseString } from '../shared'; import type { ProgramLinkNode } from './ProgramLinkNode'; export interface AccountLinkNode { readonly kind: 'accountLinkNode'; // Children. readonly program?: TProgram; // Data. readonly name: CamelCaseString; } ================================================ FILE: packages/node-types/src/linkNodes/DefinedTypeLinkNode.ts ================================================ import type { CamelCaseString } from '../shared'; import type { ProgramLinkNode } from './ProgramLinkNode'; export interface DefinedTypeLinkNode { readonly kind: 'definedTypeLinkNode'; // Children. readonly program?: TProgram; // Data. readonly name: CamelCaseString; } ================================================ FILE: packages/node-types/src/linkNodes/InstructionAccountLinkNode.ts ================================================ import type { CamelCaseString } from '../shared'; import type { InstructionLinkNode } from './InstructionLinkNode'; export interface InstructionAccountLinkNode< TInstruction extends InstructionLinkNode | undefined = InstructionLinkNode | undefined, > { readonly kind: 'instructionAccountLinkNode'; // Children. readonly instruction?: TInstruction; // Data. readonly name: CamelCaseString; } ================================================ FILE: packages/node-types/src/linkNodes/InstructionArgumentLinkNode.ts ================================================ import type { CamelCaseString } from '../shared'; import type { InstructionLinkNode } from './InstructionLinkNode'; export interface InstructionArgumentLinkNode< TInstruction extends InstructionLinkNode | undefined = InstructionLinkNode | undefined, > { readonly kind: 'instructionArgumentLinkNode'; // Children. readonly instruction?: TInstruction; // Data. readonly name: CamelCaseString; } ================================================ FILE: packages/node-types/src/linkNodes/InstructionLinkNode.ts ================================================ import type { CamelCaseString } from '../shared'; import type { ProgramLinkNode } from './ProgramLinkNode'; export interface InstructionLinkNode { readonly kind: 'instructionLinkNode'; // Children. readonly program?: TProgram; // Data. readonly name: CamelCaseString; } ================================================ FILE: packages/node-types/src/linkNodes/LinkNode.ts ================================================ import type { AccountLinkNode } from './AccountLinkNode'; import type { DefinedTypeLinkNode } from './DefinedTypeLinkNode'; import type { InstructionAccountLinkNode } from './InstructionAccountLinkNode'; import type { InstructionArgumentLinkNode } from './InstructionArgumentLinkNode'; import type { InstructionLinkNode } from './InstructionLinkNode'; import type { PdaLinkNode } from './PdaLinkNode'; import type { ProgramLinkNode } from './ProgramLinkNode'; // Link Node Registration. export type RegisteredLinkNode = | AccountLinkNode | DefinedTypeLinkNode | InstructionAccountLinkNode | InstructionArgumentLinkNode | InstructionLinkNode | PdaLinkNode | ProgramLinkNode; // Link Node Helpers. export type LinkNode = RegisteredLinkNode; ================================================ FILE: packages/node-types/src/linkNodes/PdaLinkNode.ts ================================================ import type { CamelCaseString } from '../shared'; import type { ProgramLinkNode } from './ProgramLinkNode'; export interface PdaLinkNode { readonly kind: 'pdaLinkNode'; // Children. readonly program?: TProgram; // Data. readonly name: CamelCaseString; } ================================================ FILE: packages/node-types/src/linkNodes/ProgramLinkNode.ts ================================================ import type { CamelCaseString } from '../shared'; export interface ProgramLinkNode { readonly kind: 'programLinkNode'; // Data. readonly name: CamelCaseString; } ================================================ FILE: packages/node-types/src/linkNodes/index.ts ================================================ export * from './AccountLinkNode'; export * from './DefinedTypeLinkNode'; export * from './InstructionAccountLinkNode'; export * from './InstructionArgumentLinkNode'; export * from './InstructionLinkNode'; export * from './LinkNode'; export * from './PdaLinkNode'; export * from './ProgramLinkNode'; ================================================ FILE: packages/node-types/src/pdaSeedNodes/ConstantPdaSeedNode.ts ================================================ import type { ProgramIdValueNode } from '../contextualValueNodes'; import type { TypeNode } from '../typeNodes'; import type { ValueNode } from '../valueNodes'; export interface ConstantPdaSeedNode< TType extends TypeNode = TypeNode, TValue extends ProgramIdValueNode | ValueNode = ProgramIdValueNode | ValueNode, > { readonly kind: 'constantPdaSeedNode'; // Children. readonly type: TType; readonly value: TValue; } ================================================ FILE: packages/node-types/src/pdaSeedNodes/PdaSeedNode.ts ================================================ import type { ConstantPdaSeedNode } from './ConstantPdaSeedNode'; import type { VariablePdaSeedNode } from './VariablePdaSeedNode'; // Pda Seed Node Registration. export type RegisteredPdaSeedNode = ConstantPdaSeedNode | VariablePdaSeedNode; // Pda Seed Node Helpers. export type PdaSeedNode = RegisteredPdaSeedNode; ================================================ FILE: packages/node-types/src/pdaSeedNodes/VariablePdaSeedNode.ts ================================================ import type { CamelCaseString, Docs } from '../shared'; import type { TypeNode } from '../typeNodes'; export interface VariablePdaSeedNode { readonly kind: 'variablePdaSeedNode'; // Data. readonly name: CamelCaseString; readonly docs?: Docs; // Children. readonly type: TType; } ================================================ FILE: packages/node-types/src/pdaSeedNodes/index.ts ================================================ export * from './ConstantPdaSeedNode'; export * from './PdaSeedNode'; export * from './VariablePdaSeedNode'; ================================================ FILE: packages/node-types/src/shared/bytesEncoding.ts ================================================ export type BytesEncoding = 'base16' | 'base58' | 'base64' | 'utf8'; ================================================ FILE: packages/node-types/src/shared/docs.ts ================================================ export type Docs = string[]; ================================================ FILE: packages/node-types/src/shared/index.ts ================================================ export * from './bytesEncoding'; export * from './docs'; export * from './instructionLifecycle'; export * from './stringCases'; export * from './version'; ================================================ FILE: packages/node-types/src/shared/instructionLifecycle.ts ================================================ export type InstructionLifecycle = 'archived' | 'deprecated' | 'draft' | 'live'; ================================================ FILE: packages/node-types/src/shared/stringCases.ts ================================================ export type TitleCaseString = string & { readonly ['__stringCase:codama']: 'titleCase'; }; export type PascalCaseString = string & { readonly ['__stringCase:codama']: 'pascalCase'; }; export type CamelCaseString = string & { readonly ['__stringCase:codama']: 'camelCase'; }; export type KebabCaseString = string & { readonly ['__stringCase:codama']: 'kebabCase'; }; export type SnakeCaseString = string & { readonly ['__stringCase:codama']: 'snakeCase'; }; ================================================ FILE: packages/node-types/src/shared/version.ts ================================================ type SemanticVersion = `${number}.${number}.${number}`; export type CodamaVersion = SemanticVersion; export type ProgramVersion = SemanticVersion; ================================================ FILE: packages/node-types/src/typeNodes/AmountTypeNode.ts ================================================ import type { NestedTypeNode } from './NestedTypeNode'; import type { NumberTypeNode } from './NumberTypeNode'; export interface AmountTypeNode = NestedTypeNode> { readonly kind: 'amountTypeNode'; // Data. readonly decimals: number; readonly unit?: string; // Children. readonly number: TNumber; } ================================================ FILE: packages/node-types/src/typeNodes/ArrayTypeNode.ts ================================================ import type { CountNode } from '../countNodes'; import type { TypeNode } from './TypeNode'; export interface ArrayTypeNode { readonly kind: 'arrayTypeNode'; // Children. readonly item: TItem; readonly count: TCount; } ================================================ FILE: packages/node-types/src/typeNodes/BooleanTypeNode.ts ================================================ import type { NestedTypeNode } from './NestedTypeNode'; import type { NumberTypeNode } from './NumberTypeNode'; export interface BooleanTypeNode = NestedTypeNode> { readonly kind: 'booleanTypeNode'; // Children. readonly size: TSize; } ================================================ FILE: packages/node-types/src/typeNodes/BytesTypeNode.ts ================================================ export interface BytesTypeNode { readonly kind: 'bytesTypeNode'; } ================================================ FILE: packages/node-types/src/typeNodes/DateTimeTypeNode.ts ================================================ import type { NestedTypeNode } from './NestedTypeNode'; import type { NumberTypeNode } from './NumberTypeNode'; export interface DateTimeTypeNode = NestedTypeNode> { readonly kind: 'dateTimeTypeNode'; // Children. readonly number: TNumber; } ================================================ FILE: packages/node-types/src/typeNodes/EnumEmptyVariantTypeNode.ts ================================================ import type { CamelCaseString } from '../shared'; export interface EnumEmptyVariantTypeNode { readonly kind: 'enumEmptyVariantTypeNode'; // Data. readonly name: CamelCaseString; readonly discriminator?: number; } ================================================ FILE: packages/node-types/src/typeNodes/EnumStructVariantTypeNode.ts ================================================ import type { CamelCaseString } from '../shared'; import type { NestedTypeNode } from './NestedTypeNode'; import type { StructTypeNode } from './StructTypeNode'; export interface EnumStructVariantTypeNode< TStruct extends NestedTypeNode = NestedTypeNode, > { readonly kind: 'enumStructVariantTypeNode'; // Data. readonly name: CamelCaseString; readonly discriminator?: number; // Children. readonly struct: TStruct; } ================================================ FILE: packages/node-types/src/typeNodes/EnumTupleVariantTypeNode.ts ================================================ import type { CamelCaseString } from '../shared'; import type { NestedTypeNode } from './NestedTypeNode'; import type { TupleTypeNode } from './TupleTypeNode'; export interface EnumTupleVariantTypeNode< TTuple extends NestedTypeNode = NestedTypeNode, > { readonly kind: 'enumTupleVariantTypeNode'; // Data. readonly name: CamelCaseString; readonly discriminator?: number; // Children. readonly tuple: TTuple; } ================================================ FILE: packages/node-types/src/typeNodes/EnumTypeNode.ts ================================================ import type { EnumVariantTypeNode } from './EnumVariantTypeNode'; import type { NestedTypeNode } from './NestedTypeNode'; import type { NumberTypeNode } from './NumberTypeNode'; export interface EnumTypeNode< TVariants extends EnumVariantTypeNode[] = EnumVariantTypeNode[], TSize extends NestedTypeNode = NestedTypeNode, > { readonly kind: 'enumTypeNode'; // Children. readonly variants: TVariants; readonly size: TSize; } ================================================ FILE: packages/node-types/src/typeNodes/EnumVariantTypeNode.ts ================================================ import type { EnumEmptyVariantTypeNode } from './EnumEmptyVariantTypeNode'; import type { EnumStructVariantTypeNode } from './EnumStructVariantTypeNode'; import type { EnumTupleVariantTypeNode } from './EnumTupleVariantTypeNode'; export type EnumVariantTypeNode = EnumEmptyVariantTypeNode | EnumStructVariantTypeNode | EnumTupleVariantTypeNode; ================================================ FILE: packages/node-types/src/typeNodes/FixedSizeTypeNode.ts ================================================ import type { TypeNode } from './TypeNode'; export interface FixedSizeTypeNode { readonly kind: 'fixedSizeTypeNode'; // Data. readonly size: number; // Children. readonly type: TType; } ================================================ FILE: packages/node-types/src/typeNodes/HiddenPrefixTypeNode.ts ================================================ import type { ConstantValueNode } from '../valueNodes'; import type { TypeNode } from './TypeNode'; export interface HiddenPrefixTypeNode< TType extends TypeNode = TypeNode, TPrefix extends ConstantValueNode[] = ConstantValueNode[], > { readonly kind: 'hiddenPrefixTypeNode'; // Children. readonly type: TType; readonly prefix: TPrefix; } ================================================ FILE: packages/node-types/src/typeNodes/HiddenSuffixTypeNode.ts ================================================ import type { ConstantValueNode } from '../valueNodes'; import type { TypeNode } from './TypeNode'; export interface HiddenSuffixTypeNode< TType extends TypeNode = TypeNode, TSuffix extends ConstantValueNode[] = ConstantValueNode[], > { readonly kind: 'hiddenSuffixTypeNode'; // Children. readonly type: TType; readonly suffix: TSuffix; } ================================================ FILE: packages/node-types/src/typeNodes/MapTypeNode.ts ================================================ import type { CountNode } from '../countNodes'; import type { TypeNode } from './TypeNode'; export interface MapTypeNode< TKey extends TypeNode = TypeNode, TValue extends TypeNode = TypeNode, TCount extends CountNode = CountNode, > { readonly kind: 'mapTypeNode'; // Children. readonly key: TKey; readonly value: TValue; readonly count: TCount; } ================================================ FILE: packages/node-types/src/typeNodes/NestedTypeNode.ts ================================================ import type { FixedSizeTypeNode } from './FixedSizeTypeNode'; import type { HiddenPrefixTypeNode } from './HiddenPrefixTypeNode'; import type { HiddenSuffixTypeNode } from './HiddenSuffixTypeNode'; import type { PostOffsetTypeNode } from './PostOffsetTypeNode'; import type { PreOffsetTypeNode } from './PreOffsetTypeNode'; import type { SentinelTypeNode } from './SentinelTypeNode'; import type { SizePrefixTypeNode } from './SizePrefixTypeNode'; import type { TypeNode } from './TypeNode'; export type NestedTypeNode = | FixedSizeTypeNode> | HiddenPrefixTypeNode> | HiddenSuffixTypeNode> | PostOffsetTypeNode> | PreOffsetTypeNode> | SentinelTypeNode> | SizePrefixTypeNode> | TType; ================================================ FILE: packages/node-types/src/typeNodes/NumberTypeNode.ts ================================================ export type NumberFormat = | 'f32' | 'f64' | 'i8' | 'i16' | 'i32' | 'i64' | 'i128' | 'shortU16' | 'u8' | 'u16' | 'u32' | 'u64' | 'u128'; export interface NumberTypeNode { readonly kind: 'numberTypeNode'; // Data. readonly format: TFormat; readonly endian: 'be' | 'le'; } ================================================ FILE: packages/node-types/src/typeNodes/OptionTypeNode.ts ================================================ import type { NestedTypeNode } from './NestedTypeNode'; import type { NumberTypeNode } from './NumberTypeNode'; import type { TypeNode } from './TypeNode'; export interface OptionTypeNode< TItem extends TypeNode = TypeNode, TPrefix extends NestedTypeNode = NestedTypeNode, > { readonly kind: 'optionTypeNode'; // Data. readonly fixed?: boolean; // Children. readonly item: TItem; readonly prefix: TPrefix; } ================================================ FILE: packages/node-types/src/typeNodes/PostOffsetTypeNode.ts ================================================ import type { TypeNode } from './TypeNode'; export interface PostOffsetTypeNode { readonly kind: 'postOffsetTypeNode'; // Data. readonly offset: number; readonly strategy: 'absolute' | 'padded' | 'preOffset' | 'relative'; // Children. readonly type: TType; } ================================================ FILE: packages/node-types/src/typeNodes/PreOffsetTypeNode.ts ================================================ import type { TypeNode } from './TypeNode'; export interface PreOffsetTypeNode { readonly kind: 'preOffsetTypeNode'; // Data. readonly offset: number; readonly strategy: 'absolute' | 'padded' | 'relative'; // Children. readonly type: TType; } ================================================ FILE: packages/node-types/src/typeNodes/PublicKeyTypeNode.ts ================================================ export interface PublicKeyTypeNode { readonly kind: 'publicKeyTypeNode'; } ================================================ FILE: packages/node-types/src/typeNodes/RemainderOptionTypeNode.ts ================================================ import type { TypeNode } from './TypeNode'; export interface RemainderOptionTypeNode { readonly kind: 'remainderOptionTypeNode'; // Children. readonly item: TItem; } ================================================ FILE: packages/node-types/src/typeNodes/SentinelTypeNode.ts ================================================ import type { ConstantValueNode } from '../valueNodes'; import type { TypeNode } from './TypeNode'; export interface SentinelTypeNode< TType extends TypeNode = TypeNode, TSentinel extends ConstantValueNode = ConstantValueNode, > { readonly kind: 'sentinelTypeNode'; // Children. readonly type: TType; readonly sentinel: TSentinel; } ================================================ FILE: packages/node-types/src/typeNodes/SetTypeNode.ts ================================================ import type { CountNode } from '../countNodes'; import type { TypeNode } from './TypeNode'; export interface SetTypeNode { readonly kind: 'setTypeNode'; // Children. readonly item: TItem; readonly count: TCount; } ================================================ FILE: packages/node-types/src/typeNodes/SizePrefixTypeNode.ts ================================================ import type { NestedTypeNode } from './NestedTypeNode'; import type { NumberTypeNode } from './NumberTypeNode'; import type { TypeNode } from './TypeNode'; export interface SizePrefixTypeNode< TType extends TypeNode = TypeNode, TPrefix extends NestedTypeNode = NestedTypeNode, > { readonly kind: 'sizePrefixTypeNode'; // Children. readonly type: TType; readonly prefix: TPrefix; } ================================================ FILE: packages/node-types/src/typeNodes/SolAmountTypeNode.ts ================================================ import type { NestedTypeNode } from './NestedTypeNode'; import type { NumberTypeNode } from './NumberTypeNode'; export interface SolAmountTypeNode = NestedTypeNode> { readonly kind: 'solAmountTypeNode'; // Children. readonly number: TNumber; } ================================================ FILE: packages/node-types/src/typeNodes/StringTypeNode.ts ================================================ import type { BytesEncoding } from '../shared'; export interface StringTypeNode { readonly kind: 'stringTypeNode'; // Data. readonly encoding: TEncoding; } ================================================ FILE: packages/node-types/src/typeNodes/StructFieldTypeNode.ts ================================================ import type { CamelCaseString, Docs } from '../shared'; import type { ValueNode } from '../valueNodes'; import type { TypeNode } from './TypeNode'; export interface StructFieldTypeNode< TType extends TypeNode = TypeNode, TDefaultValue extends ValueNode | undefined = ValueNode | undefined, > { readonly kind: 'structFieldTypeNode'; // Data. readonly name: CamelCaseString; readonly defaultValueStrategy?: 'omitted' | 'optional'; readonly docs?: Docs; // Children. readonly type: TType; readonly defaultValue?: TDefaultValue; } ================================================ FILE: packages/node-types/src/typeNodes/StructTypeNode.ts ================================================ import type { StructFieldTypeNode } from './StructFieldTypeNode'; export interface StructTypeNode { readonly kind: 'structTypeNode'; // Children. readonly fields: TFields; } ================================================ FILE: packages/node-types/src/typeNodes/TupleTypeNode.ts ================================================ import type { TypeNode } from './TypeNode'; export interface TupleTypeNode { readonly kind: 'tupleTypeNode'; // Children. readonly items: TItems; } ================================================ FILE: packages/node-types/src/typeNodes/TypeNode.ts ================================================ import type { DefinedTypeLinkNode } from '../linkNodes/DefinedTypeLinkNode'; import type { AmountTypeNode } from './AmountTypeNode'; import type { ArrayTypeNode } from './ArrayTypeNode'; import type { BooleanTypeNode } from './BooleanTypeNode'; import type { BytesTypeNode } from './BytesTypeNode'; import type { DateTimeTypeNode } from './DateTimeTypeNode'; import type { EnumEmptyVariantTypeNode } from './EnumEmptyVariantTypeNode'; import type { EnumStructVariantTypeNode } from './EnumStructVariantTypeNode'; import type { EnumTupleVariantTypeNode } from './EnumTupleVariantTypeNode'; import type { EnumTypeNode } from './EnumTypeNode'; import type { FixedSizeTypeNode } from './FixedSizeTypeNode'; import type { HiddenPrefixTypeNode } from './HiddenPrefixTypeNode'; import type { HiddenSuffixTypeNode } from './HiddenSuffixTypeNode'; import type { MapTypeNode } from './MapTypeNode'; import type { NumberTypeNode } from './NumberTypeNode'; import type { OptionTypeNode } from './OptionTypeNode'; import type { PostOffsetTypeNode } from './PostOffsetTypeNode'; import type { PreOffsetTypeNode } from './PreOffsetTypeNode'; import type { PublicKeyTypeNode } from './PublicKeyTypeNode'; import type { RemainderOptionTypeNode } from './RemainderOptionTypeNode'; import type { SentinelTypeNode } from './SentinelTypeNode'; import type { SetTypeNode } from './SetTypeNode'; import type { SizePrefixTypeNode } from './SizePrefixTypeNode'; import type { SolAmountTypeNode } from './SolAmountTypeNode'; import type { StringTypeNode } from './StringTypeNode'; import type { StructFieldTypeNode } from './StructFieldTypeNode'; import type { StructTypeNode } from './StructTypeNode'; import type { TupleTypeNode } from './TupleTypeNode'; import type { ZeroableOptionTypeNode } from './ZeroableOptionTypeNode'; // Standalone Type Node Registration. export type StandaloneTypeNode = | AmountTypeNode | ArrayTypeNode | BooleanTypeNode | BytesTypeNode | DateTimeTypeNode | EnumTypeNode | FixedSizeTypeNode | HiddenPrefixTypeNode | HiddenSuffixTypeNode | MapTypeNode | NumberTypeNode | OptionTypeNode | PostOffsetTypeNode | PreOffsetTypeNode | PublicKeyTypeNode | RemainderOptionTypeNode | SentinelTypeNode | SetTypeNode | SizePrefixTypeNode | SolAmountTypeNode | StringTypeNode | StructTypeNode | TupleTypeNode | ZeroableOptionTypeNode; // Type Node Registration. export type RegisteredTypeNode = | EnumEmptyVariantTypeNode | EnumStructVariantTypeNode | EnumTupleVariantTypeNode | StandaloneTypeNode | StructFieldTypeNode; /** * Type Node Helper. * This only includes type nodes that can be used as standalone types. * E.g. this excludes structFieldTypeNode, enumEmptyVariantTypeNode, etc. * It also includes the definedTypeLinkNode to compose types. */ export type TypeNode = DefinedTypeLinkNode | StandaloneTypeNode; ================================================ FILE: packages/node-types/src/typeNodes/ZeroableOptionTypeNode.ts ================================================ import type { ConstantValueNode } from '../valueNodes'; import type { TypeNode } from './TypeNode'; export interface ZeroableOptionTypeNode< TItem extends TypeNode = TypeNode, TZeroValue extends ConstantValueNode | undefined = ConstantValueNode | undefined, > { readonly kind: 'zeroableOptionTypeNode'; // Children. readonly item: TItem; readonly zeroValue?: TZeroValue; } ================================================ FILE: packages/node-types/src/typeNodes/index.ts ================================================ export * from './AmountTypeNode'; export * from './ArrayTypeNode'; export * from './BooleanTypeNode'; export * from './BytesTypeNode'; export * from './DateTimeTypeNode'; export * from './EnumEmptyVariantTypeNode'; export * from './EnumStructVariantTypeNode'; export * from './EnumTupleVariantTypeNode'; export * from './EnumTypeNode'; export * from './EnumVariantTypeNode'; export * from './FixedSizeTypeNode'; export * from './HiddenPrefixTypeNode'; export * from './HiddenSuffixTypeNode'; export * from './MapTypeNode'; export * from './NestedTypeNode'; export * from './NumberTypeNode'; export * from './OptionTypeNode'; export * from './PostOffsetTypeNode'; export * from './PreOffsetTypeNode'; export * from './PublicKeyTypeNode'; export * from './RemainderOptionTypeNode'; export * from './SentinelTypeNode'; export * from './SetTypeNode'; export * from './SizePrefixTypeNode'; export * from './SolAmountTypeNode'; export * from './StringTypeNode'; export * from './StructFieldTypeNode'; export * from './StructTypeNode'; export * from './TupleTypeNode'; export * from './TypeNode'; export * from './ZeroableOptionTypeNode'; ================================================ FILE: packages/node-types/src/valueNodes/ArrayValueNode.ts ================================================ import type { ValueNode } from './ValueNode'; export interface ArrayValueNode { readonly kind: 'arrayValueNode'; // Children. readonly items: TItems; } ================================================ FILE: packages/node-types/src/valueNodes/BooleanValueNode.ts ================================================ export interface BooleanValueNode { readonly kind: 'booleanValueNode'; // Data. readonly boolean: boolean; } ================================================ FILE: packages/node-types/src/valueNodes/BytesValueNode.ts ================================================ import type { BytesEncoding } from '../shared'; export interface BytesValueNode { readonly kind: 'bytesValueNode'; // Data. readonly data: string; readonly encoding: BytesEncoding; } ================================================ FILE: packages/node-types/src/valueNodes/ConstantValueNode.ts ================================================ import type { TypeNode } from '../typeNodes/TypeNode'; import type { ValueNode } from './ValueNode'; export interface ConstantValueNode { readonly kind: 'constantValueNode'; // Children. readonly type: TType; readonly value: TValue; } ================================================ FILE: packages/node-types/src/valueNodes/EnumValueNode.ts ================================================ import type { DefinedTypeLinkNode } from '../linkNodes'; import type { CamelCaseString } from '../shared'; import type { StructValueNode } from './StructValueNode'; import type { TupleValueNode } from './TupleValueNode'; export interface EnumValueNode< TEnum extends DefinedTypeLinkNode = DefinedTypeLinkNode, TValue extends StructValueNode | TupleValueNode | undefined = StructValueNode | TupleValueNode | undefined, > { readonly kind: 'enumValueNode'; // Data. readonly variant: CamelCaseString; // Children. readonly enum: TEnum; readonly value?: TValue; } ================================================ FILE: packages/node-types/src/valueNodes/MapEntryValueNode.ts ================================================ import type { ValueNode } from './ValueNode'; export interface MapEntryValueNode { readonly kind: 'mapEntryValueNode'; // Children. readonly key: TKey; readonly value: TValue; } ================================================ FILE: packages/node-types/src/valueNodes/MapValueNode.ts ================================================ import type { MapEntryValueNode } from './MapEntryValueNode'; export interface MapValueNode { readonly kind: 'mapValueNode'; // Children. readonly entries: TEntries; } ================================================ FILE: packages/node-types/src/valueNodes/NoneValueNode.ts ================================================ export interface NoneValueNode { readonly kind: 'noneValueNode'; } ================================================ FILE: packages/node-types/src/valueNodes/NumberValueNode.ts ================================================ export interface NumberValueNode { readonly kind: 'numberValueNode'; // Data. readonly number: number; } ================================================ FILE: packages/node-types/src/valueNodes/PublicKeyValueNode.ts ================================================ import type { CamelCaseString } from '../shared'; export interface PublicKeyValueNode { readonly kind: 'publicKeyValueNode'; // Data. readonly publicKey: string; readonly identifier?: CamelCaseString; } ================================================ FILE: packages/node-types/src/valueNodes/SetValueNode.ts ================================================ import type { ValueNode } from './ValueNode'; export interface SetValueNode { readonly kind: 'setValueNode'; // Children. readonly items: TItems; } ================================================ FILE: packages/node-types/src/valueNodes/SomeValueNode.ts ================================================ import type { ValueNode } from './ValueNode'; export interface SomeValueNode { readonly kind: 'someValueNode'; // Children. readonly value: TValue; } ================================================ FILE: packages/node-types/src/valueNodes/StringValueNode.ts ================================================ export interface StringValueNode { readonly kind: 'stringValueNode'; // Data. readonly string: string; } ================================================ FILE: packages/node-types/src/valueNodes/StructFieldValueNode.ts ================================================ import type { CamelCaseString } from '../shared'; import type { ValueNode } from './ValueNode'; export interface StructFieldValueNode { readonly kind: 'structFieldValueNode'; // Data. readonly name: CamelCaseString; // Children. readonly value: TValue; } ================================================ FILE: packages/node-types/src/valueNodes/StructValueNode.ts ================================================ import type { StructFieldValueNode } from './StructFieldValueNode'; export interface StructValueNode { readonly kind: 'structValueNode'; // Children. readonly fields: TFields; } ================================================ FILE: packages/node-types/src/valueNodes/TupleValueNode.ts ================================================ import type { ValueNode } from './ValueNode'; export interface TupleValueNode { readonly kind: 'tupleValueNode'; // Children. readonly items: TItems; } ================================================ FILE: packages/node-types/src/valueNodes/ValueNode.ts ================================================ import type { ArrayValueNode } from './ArrayValueNode'; import type { BooleanValueNode } from './BooleanValueNode'; import type { BytesValueNode } from './BytesValueNode'; import type { ConstantValueNode } from './ConstantValueNode'; import type { EnumValueNode } from './EnumValueNode'; import type { MapEntryValueNode } from './MapEntryValueNode'; import type { MapValueNode } from './MapValueNode'; import type { NoneValueNode } from './NoneValueNode'; import type { NumberValueNode } from './NumberValueNode'; import type { PublicKeyValueNode } from './PublicKeyValueNode'; import type { SetValueNode } from './SetValueNode'; import type { SomeValueNode } from './SomeValueNode'; import type { StringValueNode } from './StringValueNode'; import type { StructFieldValueNode } from './StructFieldValueNode'; import type { StructValueNode } from './StructValueNode'; import type { TupleValueNode } from './TupleValueNode'; // Standalone Value Node Registration. export type StandaloneValueNode = | ArrayValueNode | BooleanValueNode | BytesValueNode | ConstantValueNode | EnumValueNode | MapValueNode | NoneValueNode | NumberValueNode | PublicKeyValueNode | SetValueNode | SomeValueNode | StringValueNode | StructValueNode | TupleValueNode; // Value Node Registration. export type RegisteredValueNode = MapEntryValueNode | StandaloneValueNode | StructFieldValueNode; // Value Node Helper. export type ValueNode = StandaloneValueNode; ================================================ FILE: packages/node-types/src/valueNodes/index.ts ================================================ export * from './ArrayValueNode'; export * from './BooleanValueNode'; export * from './BytesValueNode'; export * from './ConstantValueNode'; export * from './EnumValueNode'; export * from './MapEntryValueNode'; export * from './MapValueNode'; export * from './NoneValueNode'; export * from './NumberValueNode'; export * from './PublicKeyValueNode'; export * from './SetValueNode'; export * from './SomeValueNode'; export * from './StringValueNode'; export * from './StructFieldValueNode'; export * from './StructValueNode'; export * from './TupleValueNode'; export * from './ValueNode'; ================================================ FILE: packages/node-types/test/GetNodeFromKind.typetest.ts ================================================ import type { GetNodeFromKind, PublicKeyTypeNode, StringTypeNode } from '../src'; // [DESCRIBE] GetNodeFromKind. { // It extracts the node from the kind. { const node = {} as GetNodeFromKind<'publicKeyTypeNode'>; node satisfies PublicKeyTypeNode; } // It extracts node unions from multiple kinds. { const node = {} as GetNodeFromKind<'publicKeyTypeNode' | 'stringTypeNode'>; node satisfies PublicKeyTypeNode | StringTypeNode; } } ================================================ FILE: packages/node-types/tsconfig.declarations.json ================================================ { "compilerOptions": { "declaration": true, "declarationMap": true, "emitDeclarationOnly": true, "outDir": "./dist/types" }, "extends": "./tsconfig.json", "include": ["src/index.ts", "src/types"] } ================================================ FILE: packages/node-types/tsconfig.json ================================================ { "$schema": "https://json.schemastore.org/tsconfig", "compilerOptions": { "lib": [] }, "display": "@codama/node-types", "extends": "../../tsconfig.json", "include": ["src", "test"] } ================================================ FILE: packages/node-types/tsup.config.ts ================================================ import { defineConfig } from 'tsup'; import { getPackageBuildConfigs } from '../../tsup.config.base'; export default defineConfig(getPackageBuildConfigs()); ================================================ FILE: packages/nodes/.gitignore ================================================ dist/ ================================================ FILE: packages/nodes/.prettierignore ================================================ dist/ test/e2e/ test-ledger/ target/ CHANGELOG.md ================================================ FILE: packages/nodes/LICENSE ================================================ MIT License Copyright (c) 2025 Codama Copyright (c) 2024 Metaplex Foundation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: packages/nodes/README.md ================================================ # Codama ➤ Nodes [![npm][npm-image]][npm-url] [![npm-downloads][npm-downloads-image]][npm-url] [npm-downloads-image]: https://img.shields.io/npm/dm/@codama/nodes.svg?style=flat [npm-image]: https://img.shields.io/npm/v/@codama/nodes.svg?style=flat&label=%40codama%2Fnodes [npm-url]: https://www.npmjs.com/package/@codama/nodes This package defines the various nodes that make up the Codama IDL. It provides types and helper functions to work with these nodes. If you are looking for a type-only version of these nodes, you can find them in the [`@codama/node-types`](../node-types) package. ## Installation ```sh pnpm install @codama/nodes ``` > [!NOTE] > This package is included in the main [`codama`](../library) package. Meaning, you already have access to its content if you are installing Codama this way. > > ```sh > pnpm install codama > ``` ## All available nodes The Codama IDL is composed of various nodes that describe different aspects of a Solana program. Some nodes are categorised together as they share a similar purpose. For instance, all the nodes that describe a data structure that can be encoded and decoded into buffers are grouped under the `TypeNode` category. Below are all of the available nodes and their documentation. Also note that you can refer to any node using the [`Node`](./docs/README.md) helper type. - [`AccountNode`](./docs/AccountNode.md) - [`DefinedTypeNode`](./docs/DefinedTypeNode.md) - [`ErrorNode`](./docs/ErrorNode.md) - [`EventNode`](./docs/EventNode.md) - [`InstructionAccountNode`](./docs/InstructionAccountNode.md) - [`InstructionArgumentNode`](./docs/InstructionArgumentNode.md) - [`InstructionByteDeltaNode`](./docs/InstructionByteDeltaNode.md) - [`InstructionNode`](./docs/InstructionNode.md) - [`InstructionRemainingAccountsNode`](./docs/InstructionRemainingAccountsNode.md) - [`PdaNode`](./docs/PdaNode.md) - [`ProgramNode`](./docs/ProgramNode.md) - [`RootNode`](./docs/RootNode.md) - [`ContextualValueNode`](./docs/contextualValueNodes/README.md) (abstract) - [`AccountBumpValueNode`](./docs/contextualValueNodes/AccountBumpValueNode.md) - [`AccountValueNode`](./docs/contextualValueNodes/AccountValueNode.md) - [`ArgumentValueNode`](./docs/contextualValueNodes/ArgumentValueNode.md) - [`ConditionalValueNode`](./docs/contextualValueNodes/ConditionalValueNode.md) - [`IdentityValueNode`](./docs/contextualValueNodes/IdentityValueNode.md) - [`PayerValueNode`](./docs/contextualValueNodes/PayerValueNode.md) - [`PdaSeedValueNode`](./docs/contextualValueNodes/PdaSeedValueNode.md) - [`PdaValueNode`](./docs/contextualValueNodes/PdaValueNode.md) - [`ProgramIdValueNode`](./docs/contextualValueNodes/ProgramIdValueNode.md) - [`ResolverValueNode`](./docs/contextualValueNodes/ResolverValueNodemds) - [`CountNode`](./docs/countNodes/README.md) (abstract) - [`FixedCountNode`](./docs/countNodes/FixedCountNode.md) - [`PrefixedCountNode`](./docs/countNodes/PrefixedCountNode.md) - [`RemainderCountNode`](./docs/countNodes/RemainderCountNodemds) - [`DiscriminatorNode`](./docs/discriminatorNodes/README.md) (abstract) - [`ConstantDiscriminatorNode`](./docs/discriminatorNodes/ConstantDiscriminatorNode.md) - [`FieldDiscriminatorNode`](./docs/discriminatorNodes/FieldDiscriminatorNode.md) - [`SizeDiscriminatorNode`](./docs/discriminatorNodes/SizeDiscriminatorNodemds) - [`LinkNode`](./docs/linkNodes/README.md) (abstract) - [`AccountLinkNode`](./docs/linkNodes/AccountLinkNode.md) - [`DefinedTypeLinkNode`](./docs/linkNodes/DefinedTypeLinkNode.md) - [`InstructionAccountLinkNode`](./docs/linkNodes/InstructionAccountLinkNode.md) - [`InstructionArgumentLinkNode`](./docs/linkNodes/InstructionArgumentLinkNode.md) - [`InstructionLinkNode`](./docs/linkNodes/InstructionLinkNode.md) - [`PdaLinkNode`](./docs/linkNodes/PdaLinkNode.md) - [`ProgramLinkNode`](./docs/linkNodes/ProgramLinkNode.md) - [`PdaSeedNode`](./docs/pdaSeedNodes/README.md) (abstract) - [`ConstantPdaSeedNode`](./docs/pdaSeedNodes/ConstantPdaSeedNode.md) - [`VariablePdaSeedNode`](./docs/pdaSeedNodes/VariablePdaSeedNode.md) - [`TypeNode`](./docs/typeNodes/README.md) (abstract) - [`AmountTypeNode`](./docs/typeNodes/AmountTypeNode.md) - [`ArrayTypeNode`](./docs/typeNodes/ArrayTypeNode.md) - [`BooleanTypeNode`](./docs/typeNodes/BooleanTypeNode.md) - [`BytesTypeNode`](./docs/typeNodes/BytesTypeNode.md) - [`DateTimeTypeNode`](./docs/typeNodes/DateTimeTypeNode.md) - [`EnumEmptyVariantTypeNode`](./docs/typeNodes/EnumEmptyVariantTypeNode.md) - [`EnumStructVariantTypeNode`](./docs/typeNodes/EnumStructVariantTypeNode.md) - [`EnumTupleVariantTypeNode`](./docs/typeNodes/EnumTupleVariantTypeNode.md) - [`EnumTypeNode`](./docs/typeNodes/EnumTypeNode.md) - [`EnumVariantTypeNode`](./docs/typeNodes/EnumVariantTypeNode.md) (abstract) - [`FixedSizeTypeNode`](./docs/typeNodes/FixedSizeTypeNode.md) - [`HiddenPrefixTypeNode`](./docs/typeNodes/HiddenPrefixTypeNode.md) - [`HiddenSuffixTypeNode`](./docs/typeNodes/HiddenSuffixTypeNode.md) - [`MapTypeNode`](./docs/typeNodes/MapTypeNode.md) - [`NestedTypeNode`](./docs/typeNodes/NestedTypeNode.md) (helper) - [`NumberTypeNode`](./docs/typeNodes/NumberTypeNode.md) - [`OptionTypeNode`](./docs/typeNodes/OptionTypeNode.md) - [`PostOffsetTypeNode`](./docs/typeNodes/PostOffsetTypeNode.md) - [`PreOffsetTypeNode`](./docs/typeNodes/PreOffsetTypeNode.md) - [`PublicKeyTypeNode`](./docs/typeNodes/PublicKeyTypeNode.md) - [`RemainderOptionTypeNode`](./docs/typeNodes/RemainderOptionTypeNode.md) - [`SentinelTypeNode`](./docs/typeNodes/SentinelTypeNode.md) - [`SetTypeNode`](./docs/typeNodes/SetTypeNode.md) - [`SizePrefixTypeNode`](./docs/typeNodes/SizePrefixTypeNode.md) - [`SolAmountTypeNode`](./docs/typeNodes/SolAmountTypeNode.md) - [`StringTypeNode`](./docs/typeNodes/StringTypeNode.md) - [`StructFieldTypeNode`](./docs/typeNodes/StructFieldTypeNode.md) - [`StructTypeNode`](./docs/typeNodes/StructTypeNode.md) - [`TupleTypeNode`](./docs/typeNodes/TupleTypeNode.md) - [`ZeroableOptionTypeNod`](./docs/typeNodes/ZeroableOptionTypeNod.md) - [`ValueNode`](./docs/valueNodes/README.md) (abstract) - [`ArrayValueNode`](./docs/valueNodes/ArrayValueNode.md) - [`BooleanValueNode`](./docs/valueNodes/BooleanValueNode.md) - [`BytesValueNode`](./docs/valueNodes/BytesValueNode.md) - [`ConstantValueNode`](./docs/valueNodes/ConstantValueNode.md) - [`EnumValueNode`](./docs/valueNodes/EnumValueNode.md) - [`MapEntryValueNode`](./docs/valueNodes/MapEntryValueNode.md) - [`MapValueNode`](./docs/valueNodes/MapValueNode.md) - [`NoneValueNode`](./docs/valueNodes/NoneValueNode.md) - [`NumberValueNode`](./docs/valueNodes/NumberValueNode.md) - [`PublicKeyValueNode`](./docs/valueNodes/PublicKeyValueNode.md) - [`SetValueNode`](./docs/valueNodes/SetValueNode.md) - [`SomeValueNode`](./docs/valueNodes/SomeValueNode.md) - [`StringValueNode`](./docs/valueNodes/StringValueNode.md) - [`StructFieldValueNode`](./docs/valueNodes/StructFieldValueNode.md) - [`StructValueNode`](./docs/valueNodes/StructValueNode.md) - [`TupleValueNode`](./docs/valueNodes/TupleValueNode.md) ================================================ FILE: packages/nodes/docs/AccountNode.md ================================================ # `AccountNode` This node defines an on-chain account. It is characterized by its name, data structure, and optional attributes such as PDA definition and account discriminators. ![Diagram](https://github.com/codama-idl/codama/assets/3642397/77974dad-212e-49b1-8e41-5d466c273a02) ## Attributes ### Data | Attribute | Type | Description | | --------- | ----------------- | ----------------------------------------------------------------------------------- | | `kind` | `"accountNode"` | The node discriminator. | | `name` | `CamelCaseString` | The name of the account. | | `docs` | `string[]` | Markdown documentation for the account. | | `size` | `number` | (Optional) The size of the account in bytes, if the account's data length is fixed. | ### Children | Attribute | Type | Description | | ---------------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `data` | [`NestedTypeNode`](./typeNodes/NestedTypeNode.md)<[`StructTypeNode`](./typeNodes/StructTypeNode.md)> | The type node that describes the account's data. Note that it must be a struct so we can access its fields via other nodes. | | `pda` | [`PdaLinkNode`](./linkNodes/PdaLinkNode.md) | (Optional) The link node that describes the account's PDA, if its address is derived from one. | | `discriminators` | [`DiscriminatorNode`](./discriminatorNodes/README.md)[] | (Optional) The nodes that distinguish this account from others in the program. If multiple discriminators are provided, they are combined using a logical AND operation. | ## Functions ### `accountNode(input)` Helper function that creates a `AccountNode` object from an input object. ```ts const node = accountNode({ name: 'myCounter', data: structTypeNode([ structFieldTypeNode({ name: 'authority', type: publicKeyTypeNode() }), structFieldTypeNode({ name: 'value', type: numberTypeNode('u64') }), ]), }); ``` ## Examples ### A fixed-size account ```ts const node = accountNode({ name: 'token', data: structTypeNode([ structFieldTypeNode({ name: 'mint', type: publicKeyTypeNode() }), structFieldTypeNode({ name: 'owner', type: publicKeyTypeNode() }), structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64') }), ]), discriminators: [sizeDiscriminatorNode(72)], size: 72, }); ``` ### An account with a linked PDA ```ts programNode({ name: 'myProgram', accounts: [ accountNode({ name: 'token', data: structTypeNode([structFieldTypeNode({ name: 'authority', type: publicKeyTypeNode() })]), pda: pdaLinkNode('myPda'), }), ], pdas: [ pdaNode({ name: 'myPda', seeds: [ constantPdaSeedNodeFromString('utf8', 'token'), variablePdaSeedNode('authority', publicKeyTypeNode()), ], }), ], }); ``` ================================================ FILE: packages/nodes/docs/DefinedTypeNode.md ================================================ # `DefinedTypeNode` This node defines a named type that can be reused in other types using a [`DefinedTypeLinkNode`](./linkNodes/DefinedTypeLinkNode.md). ![Diagram](https://github.com/codama-idl/codama/assets/3642397/6049cf77-9a70-4915-8276-dd571d2f8828) ## Attributes ### Data | Attribute | Type | Description | | --------- | ------------------- | ------------------------------------ | | `kind` | `"definedTypeNode"` | The node discriminator. | | `name` | `CamelCaseString` | The name of the reusable type. | | `docs` | `string[]` | Markdown documentation for the type. | ### Children | Attribute | Type | Description | | --------- | ----------------------------------- | ----------------------------- | | `type` | [`TypeNode`](./typeNodes/README.md) | The concrete type definition. | ## Functions ### `definedTypeNode(input)` Helper function that creates a `DefinedTypeNode` object from an input object. ```ts const node = definedTypeNode({ name: 'person', docs: ['This type describes a Person.'], type: structTypeNode([ structFieldTypeNode({ name: 'name', type: stringTypeNode('utf8') }), structFieldTypeNode({ name: 'age', type: numberTypeNode('u8') }), ]), }); ``` ================================================ FILE: packages/nodes/docs/ErrorNode.md ================================================ # `ErrorNode` This node defines an error that can be returned by a program. ![Diagram](https://github.com/codama-idl/codama/assets/3642397/0bde98ea-0327-404b-bf38-137d105826b0) ## Attributes ### Data | Attribute | Type | Description | | --------- | ----------------- | ------------------------------------------------ | | `kind` | `"errorNode"` | The node discriminator. | | `name` | `CamelCaseString` | The name of the error. | | `code` | `number` | The error code. | | `message` | `string` | A human-friendly message describing the error. | | `docs` | `string[]` | Additional Markdown documentation for the error. | ### Children _This node has no children._ ## Functions ### `errorNode(input)` Helper function that creates a `ErrorNode` object from an input object. ```ts const node = errorNode({ name: 'invalidAmountArgument', code: 1, message: 'The amount argument is invalid.', }); ``` ================================================ FILE: packages/nodes/docs/EventNode.md ================================================ # `EventNode` This node represents an event emitted by a program. ## Attributes ### Data | Attribute | Type | Description | | --------- | ----------------- | ------------------------------------------------ | | `kind` | `"eventNode"` | The node discriminator. | | `name` | `CamelCaseString` | The name of the event. | | `docs` | `string[]` | Additional Markdown documentation for the event. | ### Children | Attribute | Type | Description | | ---------------- | ------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `data` | [`TypeNode`](./typeNodes/README.md) | The type node that describes the event payload. | | `discriminators` | [`DiscriminatorNode`](./discriminatorNodes/README.md)[] | (Optional) The nodes that distinguish this event from others in the program. If multiple discriminators are provided, they are combined using a logical AND operation. | ## Functions ### `eventNode(input)` Helper function that creates an `EventNode` object from an input object. ```ts const node = eventNode({ name: 'transferEvent', data: structTypeNode([ structFieldTypeNode({ name: 'authority', type: publicKeyTypeNode() }), structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64') }), ]), }); ``` ## Examples ### An event with a struct payload ```ts eventNode({ name: 'transferEvent', data: structTypeNode([ structFieldTypeNode({ name: 'authority', type: publicKeyTypeNode() }), structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64') }), ]), }); ``` ### An event with a hidden prefix discriminator ```ts eventNode({ name: 'transferEvent', data: hiddenPrefixTypeNode(structTypeNode([structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64') })]), [ constantValueNode(fixedSizeTypeNode(bytesTypeNode(), 8), bytesValueNode('base16', '0102030405060708')), ]), discriminators: [ constantDiscriminatorNode( constantValueNode(fixedSizeTypeNode(bytesTypeNode(), 8), bytesValueNode('base16', '0102030405060708')), ), ], }); ``` ================================================ FILE: packages/nodes/docs/InstructionAccountNode.md ================================================ # `InstructionAccountNode` This node defines an account used by an instruction. It is characterized by its name and various requirements such as whether it needs to be writable or a signer. ![Diagram](https://github.com/codama-idl/codama/assets/3642397/4656a08b-2f89-49c2-b428-5378cb1a0b9e) ## Attributes ### Data | Attribute | Type | Description | | ------------ | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `kind` | `"instructionAccountNode"` | The node discriminator. | | `name` | `CamelCaseString` | The name of the instruction account. | | `isWritable` | `boolean` | Whether of not the account needs to be writable. | | `isSigner` | `boolean` \| `"either"` | Whether or not the account needs to be a signer. If the value `"either"` is provided, the account can be either a signer or not depending on the context. | | `isOptional` | `boolean` | (Optional) Whether or not the account is optional. If this is `true`, the account should be handled as an optional account according to the `optionalAccountStrategy` attribute of the [`InstructionNode`.](./InstructionNode.md) Defaults to `false`. | | `docs` | `string[]` | Markdown documentation for the instruction account. | ### Children | Attribute | Type | Description | | -------------- | ---------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | | `defaultValue` | [`InstructionInputValueNode`](./contextualValueNodes/InstructionInputValueNode.md) | (Optional) A default value for the account should this account not be provided when constructing the instruction. | ## Functions ### `instructionAccountNode(input)` Helper function that creates a `InstructionAccountNode` object from an input object. ```ts const node = instructionAccountNode({ name: 'authority', isWritable: false, isSigner: true, docs: ['This account that has the authority to perform this instruction.'], }); ``` ## Examples ### An optional account ```ts instructionAccountNode({ name: 'freezeAuthority', isWritable: false, isSigner: false, isOptional: true, docs: ['The freeze authority to set on the asset, if any.'], }); ``` ### An optional signer account ```ts instructionAccountNode({ name: 'owner', isWritable: true, isSigner: 'either', docs: ['The owner of the asset. The owner must only sign the transaction if the asset is being updated.'], }); ``` ================================================ FILE: packages/nodes/docs/InstructionArgumentNode.md ================================================ # `InstructionArgumentNode` This node defines an argument that is passed to an instruction. When all arguments are combined and serialized next to each other, they form the instruction's data. ![Diagram](https://github.com/codama-idl/codama/assets/3642397/7e2def82-949a-4663-bdc3-ac599d39d2d2) ## Attributes ### Data | Attribute | Type | Description | | ---------------------- | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `kind` | `"instructionArgumentNode"` | The node discriminator. | | `name` | `CamelCaseString` | The name of the instruction argument. | | `docs` | `string[]` | Markdown documentation for the instruction argument. | | `defaultValueStrategy` | `"optional"` \| `"omitted"` | (Optional) The strategy to use when a default value is provided for the argument. `"optional"` means that the argument's default value may be overriden by a provided argument, while `"omitted"` means that no argument should be provided and the default value should always be the argument's value. Defaults to `"optional"`. | ### Children | Attribute | Type | Description | | -------------- | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | | `type` | [`TypeNode`](./typeNodes/README.md) | The `TypeNode` that describes the argument's data. | | `defaultValue` | [`InstructionInputValueNode`](./contextualValueNodes/InstructionInputValueNode.md) | (Optional) A default value for the argument should this argument not be provided when constructing the instruction. | ## Functions ### `instructionArgumentNode(input)` Helper function that creates a `InstructionArgumentNode` object from an input object. ```ts const node = instructionArgumentNode({ name: 'amount', type: numberTypeNode('u64'), docs: ['This amount of tokens to transfer.'], }); ``` ## Examples ### An argument with a default value ```ts instructionArgumentNode({ name: 'amount', type: numberTypeNode('u64'), defaultValue: numberValueNode(0), }); ``` ### An argument with an omitted default value ```ts instructionArgumentNode({ name: 'instructionDiscriminator', type: numberTypeNode('u8'), defaultValue: numberValueNode(42), defaultValueStrategy: 'omitted', }); ``` ================================================ FILE: packages/nodes/docs/InstructionByteDeltaNode.md ================================================ # `InstructionByteDeltaNode` This node represents a difference in bytes stored on-chain from executing an instruction. For instance, if an instruction creates a new account of 42 bytes, this node can provide this information. This enables clients to allocate the right amount of lamports to cover the cost of executing the instruction. ## Attributes ### Data | Attribute | Type | Description | | ------------ | ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `kind` | `"instructionByteDeltaNode"` | The node discriminator. | | `withHeader` | `boolean` | (Optional) Whether or not we should add the account header size — i.e. 128 bytes — to the value. Default to `false` when the value is a `ResolverValueNode` and `true` otherwise. | | `subtract` | `boolean` | (Optional) Whether or not the provided value should be subtracted from the total byte delta. Defaults to `false`. | ### Children | Attribute | Type | Description | | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `value` | [`AccountLinkNode`](./linkNodes/AccountLinkNode.md) \| [`ArgumentValueNode`](./contextualValueNodes/ArgumentValueNode.md) \| [`NumberValueNode`](./valueNodes/NumberValueNode.md) \| [`ResolverValueNode`](./contextualValueNodes/ResolverValueNode.md) | The value representing the byte delta. If an `AccountLinkNode` is used, the size of the linked account will be used. If an `ArgumentValueNode` is used, the value of the instruction argument will be used. If a `NumberValueNode` is used, that explicit number will be used. Otherwise, a `ResolverValueNode` can be used as a fallback for more complex values. | ## Functions ### `instructionByteDeltaNode(value, options?)` Helper function that creates a `InstructionByteDeltaNode` object from a value node and some options. ```ts const node = instructionByteDeltaNode(numberValueNode(42), { withHeader: false }); ``` ## Examples ### A byte delta that represents a new account ```ts instructionByteDeltaNode(accountLinkNode('token')); ``` ### A byte delta that represents an account deletion ```ts instructionByteDeltaNode(accountLinkNode('token'), { subtract: true }); ``` ### A byte delta that uses an argument value to increase the space of an account ```ts instructionByteDeltaNode(argumentValueNode('additionalSpace'), { withHeader: false }); ``` ================================================ FILE: packages/nodes/docs/InstructionNode.md ================================================ # `InstructionNode` This node represents an instruction in a program. ![Diagram](https://github.com/codama-idl/codama/assets/3642397/0d8edced-cfa4-4500-b80c-ebc56181a338) ## Attributes ### Data | Attribute | Type | Description | | ------------------------- | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `kind` | `"instructionNode"` | The node discriminator. | | `name` | `CamelCaseString` | The name of the instruction. | | `docs` | `string[]` | Markdown documentation for the instruction. | | `optionalAccountStrategy` | `"omitted"` \| `"programId"` | (Optional) Determines how to handle optional accounts. `"omitted"` means optional accounts that are not provided will be omitted from the list of accounts, `"programId"` means they will be replaced by the address of the program to ensure account ordering with only 1 byte of overhead. Defaults to `"programId"`. | ### Children | Attribute | Type | Description | | ------------------- | ----------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `accounts` | [`InstructionAccountNode`](./InstructionAccountNode.md)[] | The list of accounts that the instruction uses and their requirements. | | `arguments` | [`InstructionArgumentNode`](./InstructionArgumentNode.md)[] | The arguments the constitute the instruction's data. | | `extraArguments` | [`InstructionArgumentNode`](./InstructionArgumentNode.md)[] | (Optional) Additional arguments that do not contribute to the instruction's data but may help when defining default values. | | `remainingAccounts` | [`InstructionRemainingAccountsNode`](./InstructionRemainingAccountsNode.md)[] | (Optional) The list of dynamic remaining accounts requirements for the instruction. For instance, an instruction may have a variable number of signers at the end of the accounts list. | | `byteDeltas` | [`InstructionByteDeltaNode`](./InstructionByteDeltaNode.md)[] | (Optional) The list of byte variations that the instruction causes. They should all be added together unless the `subtract` attribute is used. | | `discriminators` | [`DiscriminatorNode`](./DiscriminatorNode.md)[] | (Optional) The nodes that distinguish this instruction from others in the program. If multiple discriminators are provided, they are combined using a logical AND operation. | | `status` | [`InstructionStatusNode`](./InstructionStatusNode.md) | (Optional) The status of the instruction and an optional message about that status. | | `subInstructions` | [`InstructionNode`](./InstructionNode.md)[] | (Optional) A list of nested instructions should this instruction be split into multiple sub-instructions to define distinct scenarios. | ## Functions ### `instructionNode(input)` Helper function that creates a `InstructionNode` object from an input object. ```ts const node = instructionNode({ name: 'increment', accounts: [ instructionAccountNode({ name: 'counter', isWritable: true, isSigner: false }), instructionAccountNode({ name: 'authority', isWritable: false, isSigner: true }), ], arguments: [instructionArgumentNode({ name: 'amount', type: numberTypeNode('u8') })], }); ``` ### `getAllInstructionArguments(instruction)` Helper function that returns all arguments — including extra arguments — of an instruction as a `InstructionArgumentNode[]`. ```ts const allArguments = getAllInstructionArguments(instruction); ``` ### `getAllInstructionsWithSubs()` Helper function that returns all instructions with their nested sub-instructions, if any. It can be called on a `RootNode`, `ProgramNode`, or `InstructionNode`. ```ts const allInstructionsFromTheRoot = getAllInstructionsWithSubs(rootNode); const allInstructionsFromThisProgram = getAllInstructionsWithSubs(programNode); const allInstructionsFromThisInstruction = getAllInstructionsWithSubs(instructionNode); ``` ## Examples ### An instruction with a u8 discriminator ```ts instructionNode({ name: 'increment', accounts: [ instructionAccountNode({ name: 'counter', isWritable: true, isSigner: true }), instructionAccountNode({ name: 'authority', isWritable: false, isSigner: false }), ], arguments: [ instructionArgumentNode({ name: 'discriminator', type: numberTypeNode('u8'), defaultValue: numberValueNode(42), defaultValueStrategy: 'omitted', }), ], }); ``` ### An instruction that creates a new account ```ts instructionNode({ name: 'createCounter', accounts: [ instructionAccountNode({ name: 'counter', isWritable: true, isSigner: true }), instructionAccountNode({ name: 'authority', isWritable: false, isSigner: false }), ], byteDeltas: [instructionByteDeltaNode(accountLinkNode('counter'))], }); ``` ### An instruction with omitted optional accounts ```ts instructionNode({ name: 'initialize', accounts: [ instructionAccountNode({ name: 'counter', isWritable: true, isSigner: true }), instructionAccountNode({ name: 'authority', isWritable: false, isSigner: false }), instructionAccountNode({ name: 'freezeAuthority', isWritable: false, isSigner: false, isOptional: true }), ], optionalAccountStrategy: 'omitted', }); ``` ### An instruction with remaining signers ```ts instructionNode({ name: 'multisigIncrement', accounts: [instructionAccountNode({ name: 'counter', isWritable: true, isSigner: false })], remainingAccounts: [instructionRemainingAccountsNode(argumentValueNode('authorities'), { isSigner: true })], }); ``` ### An instruction with nested versioned instructions ```ts instructionNode({ name: 'increment', accounts: [ instructionAccountNode({ name: 'counter', isWritable: true, isSigner: 'either' }), instructionAccountNode({ name: 'authority', isWritable: false, isSigner: true }), ], arguments: [ instructionArgumentNode({ name: 'version', type: numberTypeNode('u8') }), instructionArgumentNode({ name: 'amount', type: numberTypeNode('u8') }), ], subInstructions: [ instructionNode({ name: 'incrementV1', accounts: [instructionAccountNode({ name: 'counter', isWritable: true, isSigner: true })], arguments: [ instructionArgumentNode({ name: 'version', type: numberTypeNode('u8'), defaultValue: numberValueNode(0), defaultValueStrategy: 'omitted', }), instructionArgumentNode({ name: 'amount', type: numberTypeNode('u8') }), ], }), instructionNode({ name: 'incrementV2', accounts: [ instructionAccountNode({ name: 'counter', isWritable: true, isSigner: false }), instructionAccountNode({ name: 'authority', isWritable: false, isSigner: true }), ], arguments: [ instructionArgumentNode({ name: 'version', type: numberTypeNode('u8'), defaultValue: numberValueNode(1), defaultValueStrategy: 'omitted', }), instructionArgumentNode({ name: 'amount', type: numberTypeNode('u8') }), ], }), ], }); ``` ### A deprecated instruction ```ts instructionNode({ name: 'oldIncrement', status: instructionStatusNode( 'deprecated', 'Use the `increment` instruction instead. This will be removed in v3.0.0.', ), accounts: [instructionAccountNode({ name: 'counter', isWritable: true, isSigner: false })], arguments: [instructionArgumentNode({ name: 'amount', type: numberTypeNode('u8') })], }); ``` ### An archived instruction ```ts instructionNode({ name: 'legacyTransfer', status: instructionStatusNode( 'archived', 'This instruction was removed in v2.0.0. It is kept here for historical parsing.', ), accounts: [ instructionAccountNode({ name: 'source', isWritable: true, isSigner: true }), instructionAccountNode({ name: 'destination', isWritable: true, isSigner: false }), ], arguments: [instructionArgumentNode({ name: 'amount', type: numberTypeNode('u64') })], }); ``` ### A draft instruction ```ts instructionNode({ name: 'experimentalFeature', status: instructionStatusNode('draft', 'This instruction is under development and may change.'), accounts: [instructionAccountNode({ name: 'config', isWritable: true, isSigner: true })], arguments: [], }); ``` ================================================ FILE: packages/nodes/docs/InstructionRemainingAccountsNode.md ================================================ # `InstructionRemainingAccountsNode` This node represents a list of remaining accounts for an instruction. It can be used to represent a dynamic list of accounts that are not explicitly defined in the instruction but may be required for the instruction to execute. ## Attributes ### Data | Attribute | Type | Description | | ------------ | ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `kind` | `"instructionRemainingAccountsNode"` | The node discriminator. | | `docs` | `string[]` | Markdown documentation explaining the remaining accounts of an instruction. | | `isOptional` | `boolean` | (Optional) Whether the remaining accounts are optional. Defaults to `false`. | | `isSigner` | `boolean` \| `"either"` | (Optional) Whether the remaining accounts are signers. If `true`, all are. If `false`, none are. If `"either"`, they may each either be a signer or not. Defaults to `false`. | ### Children | Attribute | Type | Description | | --------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `value` | [`ArgumentValueNode`](./contextualValueNodes/ArgumentValueNode.md) \| [`ResolverValueNode`](./contextualValueNodes/ResolverValueNode.md) | The node representing how these remaining accounts are gathered. If a `ArgumentValueNode` is provided, a new argument will be used to represent this array of accounts from the provided name. Otherwise, a `ResolverValueNode` can be used as a fallback to represent more complex scenarios. | ## Functions ### `instructionRemainingAccountsNode(value, options?)` Helper function that creates a `InstructionRemainingAccountsNode` object from a value node and some options. ```ts const node = instructionRemainingAccountsNode(argumentValueNode('signers'), { isSigner: true, isOptional: true, }); ``` ## Examples ### Optional remaining signers ```ts instructionRemainingAccountsNode(argumentValueNode('authorities'), { isSigner: true, isOptional: true, }); ``` ### Remaining accounts that may or may not be signers ```ts instructionRemainingAccountsNode(argumentValueNode('authorities'), { isSigner: 'either', }); ``` ### Remaining accounts using a resolver ```ts instructionRemainingAccountsNode( resolverValueNode('resolveTransferRemainingAccounts', { docs: ['Provide authorities as remaining accounts if and only if the asset has a multisig set up.'], dependsOn: [argumentValueNode('hasMultisig'), argumentValueNode('authorities')], }), ); ``` ================================================ FILE: packages/nodes/docs/InstructionStatusNode.md ================================================ # `InstructionStatusNode` This node represents the status of an instruction along with an optional message. ## Attributes ### Data | Attribute | Type | Description | | ----------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `kind` | `"instructionStatusNode"` | The node discriminator. | | `lifecycle` | `"live"` \| `"deprecated"` \| `"archived"` \| `"draft"` | The lifecycle status of the instruction. `"live"` means accessible (the default), `"deprecated"` means about to be archived, `"archived"` means no longer accessible but kept for historical parsing, `"draft"` means not fully implemented yet. | | `message` | `string` | (Optional) Additional information about the current status for program consumers. | ## Functions ### `instructionStatusNode(lifecycle, message?)` Helper function that creates an `InstructionStatusNode` object. ```ts const statusNode = instructionStatusNode('deprecated', 'Use the newInstruction instead'); ``` ## Examples ### A live instruction (no status needed) For live instructions, you typically don't need to set a status at all: ```ts instructionNode({ name: 'transfer', accounts: [...], arguments: [...], }); ``` ### A deprecated instruction ```ts instructionNode({ name: 'oldTransfer', status: instructionStatusNode('deprecated', 'Use the `transfer` instruction instead. This will be removed in v3.0.0.'), accounts: [...], arguments: [...], }); ``` ### An archived instruction ```ts instructionNode({ name: 'legacyTransfer', status: instructionStatusNode('archived', 'This instruction was removed in v2.0.0. It is kept here for historical parsing.'), accounts: [...], arguments: [...], }); ``` ### A draft instruction ```ts instructionNode({ name: 'experimentalFeature', status: instructionStatusNode('draft', 'This instruction is under development and may change.'), accounts: [...], arguments: [...], }); ``` ### Status without a message ```ts instructionNode({ name: 'someInstruction', status: instructionStatusNode('deprecated'), accounts: [...], arguments: [...], }); ``` ================================================ FILE: packages/nodes/docs/PdaNode.md ================================================ # `PdaNode` This node provides a definition for a specific Program-Derived Address (PDA). It is characterized by a name and a list of seeds that can either be constant or variable. ![Diagram](https://github.com/codama-idl/codama/assets/3642397/4f7c9718-1ffa-4f2c-aa45-71b3ce204219) ## Attributes ### Data | Attribute | Type | Description | | ----------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------- | | `kind` | `"pdaNode"` | The node discriminator. | | `name` | `CamelCaseString` | The name of the PDA. | | `docs` | `string[]` | Markdown documentation for the PDA. | | `programId` | `string` | (Optional) The address of the program the PDA should derive from. Defaults to the address of the nearest `ProgramNode` ancestor. | ### Children | Attribute | Type | Description | | --------- | ------------------------------------------- | --------------------- | | `seeds` | [`PdaSeedNode`](./pdaSeedNodes/README.md)[] | The seeds of the PDA. | ## Functions ### `pdaNode(input)` Helper function that creates a `pdaNode` object from an input object. ```ts const node = pdaNode({ name: 'counter', seeds: [variablePdaSeedNode('authority', publicKeyTypeNode())], docs: ['The counter PDA derived from its authority.'], }); ``` ## Examples ### A PDA with constant and variable seeds ```ts pdaNode({ name: 'ticket', seeds: [ constantPdaSeedNodeFromString('utf8', 'raffles'), variablePdaSeedNode('raffle', publicKeyTypeNode()), constantPdaSeedNodeFromString('utf8', 'tickets'), variablePdaSeedNode('ticketNumber', numberTypeNode('u32')), ], }); ``` ### A PDA with no seeds ```ts pdaNode({ name: 'seedlessPda', seeds: [], }); ``` ================================================ FILE: packages/nodes/docs/ProgramNode.md ================================================ # `ProgramNode` This node represents an entire program deployed on-chain. It defines all elements of a program such as accounts, instructions, PDAs, events, errors, etc. ![Diagram](https://github.com/codama-idl/codama/assets/3642397/37ec38ea-66df-4c08-81c3-822ef4388580) ## Attributes ### Data | Attribute | Type | Description | | ----------- | ----------------------- | ---------------------------------------------------------------------------- | | `kind` | `"programNode"` | The node discriminator. | | `name` | `CamelCaseString` | The name of the program. | | `publicKey` | `string` | The 32-bytes address of the program base58 encoded. | | `version` | `\d.\d.\d` | The semantic version of the program being defined. | | `docs` | `string[]` | Markdown documentation for the program. | | `origin` | `"anchor"` \| `"shank"` | (Optional) An optional attribute tells us how this program node was created. | ### Children | Attribute | Type | Description | | -------------- | ------------------------------------------- | ------------------------------------------------------------- | | `accounts` | [`AccountNode`](./AccountNode.md)[] | The accounts created and managed by the program. | | `instructions` | [`InstructionNode`](./InstructionNode.md)[] | The instructions that allows us to interact with the program. | | `definedTypes` | [`DefinedTypeNode`](./DefinedTypeNode.md)[] | Some reusable types defined by the program. | | `pdas` | [`PdaNode`](./PdaNode.md)[] | The Program-Derived Addresses (PDAs) used by the program. | | `events` | [`EventNode`](./EventNode.md)[] | The events that can be emitted by the program. | | `errors` | [`ErrorNode`](./ErrorNode.md)[] | The errors that can be thrown by the program. | ## Functions ### `programNode(input)` Helper function that creates a `ProgramNode` object from an input object ```ts const node = programNode({ name: 'counter', publicKey: '7ovtg4pFqjQdSwFAUCu8gTnh5thZHzAyJFXy3Ssnj3yK', version: '1.42.6', accounts: [], instructions: [], definedTypes: [], pdas: [], events: [], errors: [], }); ``` ### `getAllPrograms(node)` Helper function that returns all `ProgramNodes` under a given node. This can be a `RootNode`, a `ProgramNode` — returning itself in an array — or an array of `ProgramNode`. ```ts const allPrograms = getAllPrograms(rootNode); ``` ### `getAllPdas(node)` Helper function that returns all `PdaNodes` under a given node. This can be a `RootNode`, a `ProgramNode` or an array of `ProgramNode`. ```ts const allPdas = getAllPdas(rootNode); ``` ### `getAllAccounts(node)` Helper function that returns all `AccountNodes` under a given node. This can be a `RootNode`, a `ProgramNode` or an array of `ProgramNode`. ```ts const allAccounts = getAllAccounts(rootNode); ``` ### `getAllEvents(node)` Helper function that returns all `EventNodes` under a given node. This can be a `RootNode`, a `ProgramNode` or an array of `ProgramNode`. ```ts const allEvents = getAllEvents(rootNode); ``` ### `getAllDefinedTypes(node)` Helper function that returns all `DefinedTypeNodes` under a given node. This can be a `RootNode`, a `ProgramNode` or an array of `ProgramNode`. ```ts const allDefinedTypes = getAllDefinedTypes(rootNode); ``` ### `getAllInstructions(node)` Helper function that returns all `InstructionNodes` under a given node. This can be a `RootNode`, a `ProgramNode` or an array of `ProgramNode`. ```ts const allInstructions = getAllInstructions(rootNode); ``` ### `getAllErrors(node)` Helper function that returns all `ErrorNodes` under a given node. This can be a `RootNode`, a `ProgramNode` or an array of `ProgramNode`. ```ts const allErrors = getAllErrors(rootNode); ``` ================================================ FILE: packages/nodes/docs/README.md ================================================ # `Node` (abstract) The `Node` type helper represents all available nodes. Note that `Node` is a type alias and cannot be used directly as a node. Instead you may use any node to satisfy the `Node` type. You can [see all available nodes here](../README.md#documentation). ## Functions Some helper functions are also available to work with nodes. ### `isNode(node, kind)` Type guard that checks if a node is of a specific kind or part of a list of kinds. If the provided node is `null` or `undefined`, the function returns `false`. ```ts isNode(stringTypeNode('utf8'), 'stringTypeNode'); // true. isNode(stringTypeNode('utf8'), 'numberTypeNode'); // false. isNode(stringTypeNode('utf8'), ['stringTypeNode', 'numberTypeNode']); // true. isNode(null, 'stringTypeNode'); // false. isNode(undefined, 'stringTypeNode'); // false. ``` ### `assertIsNode(node, kind)` Type guard that asserts that a node is of a specific kind or part of a list of kinds. If the provided node is `null` or `undefined`, the function throws an error. ```ts assertIsNode(stringTypeNode('utf8'), 'stringTypeNode'); // Ok. assertIsNode(stringTypeNode('utf8'), 'numberTypeNode'); // Throws an error. assertIsNode(stringTypeNode('utf8'), ['stringTypeNode', 'numberTypeNode']); // Ok. assertIsNode(null, 'stringTypeNode'); // Throws an error. assertIsNode(undefined, 'stringTypeNode'); // Throws an error. ``` ### `isNodeFilter(kind)` This function returns a function that acts as the `isNode` function but with a predefined kind or list of kinds to check against. This is a useful function to use in combination with array functions like `filter`. ```ts myNodes.filter(isNodeFilter('stringTypeNode')); // Keep only string type nodes. myNodes.filter(isNodeFilter(['stringTypeNode', 'numberTypeNode'])); // Keep only string and number type nodes. ``` ### `assertIsNodeFilter(kind)` This function returns a function that acts as the `assertIsNode` function but with a predefined kind or list of kinds to check against. This is a useful function to use in combination with array functions like `filter`. ```ts myNodes.filter(assertIsNodeFilter('stringTypeNode')); // Fail if there are non-string type node. myNodes.filter(assertIsNodeFilter(['stringTypeNode', 'numberTypeNode'])); // Fail if there are nodes that are not string or number type nodes. ``` ### `removeNullAndAssertIsNodeFilter(kind)` This function acts like the `assertIsNodeFilter` function below but removes `null` and `undefined` values before asserting the kind or kinds. ```ts const myNodes = [null, stringTypeNode('utf8'), undefined, stringTypeNode('base58')]; myNodes.filter(removeNullAndAssertIsNodeFilter('stringTypeNode')); // Ok and removes null and undefined values. myNodes.filter(removeNullAndAssertIsNodeFilter('numberTypeNode')); // Throws an error. myNodes.filter(removeNullAndAssertIsNodeFilter(['stringTypeNode', 'numberTypeNode'])); // Ok and removes null and undefined values. ``` ================================================ FILE: packages/nodes/docs/RootNode.md ================================================ # `RootNode` This node represents the starting point of the Codama IDL. It contains a single `ProgramNode` which the Codama IDL is describing as well as any additional programs that may be referenced by the main program. This node is also responsible for setting the standard and version of the IDL. ![Diagram](https://github.com/codama-idl/codama/assets/3642397/96c43c75-5925-4b6b-a1e0-8b8c61317cfe) ## Attributes ### Data | Attribute | Type | Description | | ---------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `kind` | `"rootNode"` | The node discriminator. | | `standard` | `"codama"` | The IDL standard used by the `RootNode` which is always `"codama"`. This can help other communities fork the Codama standard. | | `version` | `\d.\d.\d` | The semantic version of the standard used by the `RootNode`. That is — unless a different standard is used — this will be the Codama version from which this entire tree of node was created. | ### Children | Attribute | Type | Description | | -------------------- | ----------------------------------- | ----------------------------------------------------------------------- | | `program` | [`ProgramNode`](./ProgramNode.md) | The main program being described. | | `additionalPrograms` | [`ProgramNode`](./ProgramNode.md)[] | (Optional) Additional programs that are referenced by the main program. | ## Functions ### `rootNode(program, additionalPrograms?)` Helper function that creates a `RootNode` object from a `ProgramNode` and an optional array of additional `ProgramNodes`. Note that the `standard` is automatically set to `"codama"` and the `version` is set to the Codama version installed. ```ts const node = rootNode(programNode({ ... })); ``` ## Examples ### A root node with a single program ```ts const node = rootNode( programNode({ name: 'counter', publicKey: '2R3Ui2TVUUCyGcZdopxJauk8ZBzgAaHHZCVUhm5ifPaC', version: '1.0.0', accounts: [ accountNode({ name: 'counter', data: structTypeNode([ structFieldTypeNode({ name: 'authority', type: publicKeyTypeNode() }), structFieldTypeNode({ name: 'value', type: numberTypeNode('u32') }), ]), }), ], instructions: [ instructionNode({ name: 'create' /* ... */ }), instructionNode({ name: 'increment' /* ... */ }), instructionNode({ name: 'transferAuthority' /* ... */ }), instructionNode({ name: 'delete' /* ... */ }), ], }), ); ``` ================================================ FILE: packages/nodes/docs/_template.md ================================================ # `SomeNode` This node represents TODO. ## Attributes ### Data | Attribute | Type | Description | | --------- | ----------------- | ------------------------------------ | | `kind` | `"someNode"` | The node discriminator. | | `name` | `CamelCaseString` | The name of the node. | | `docs` | `string[]` | Markdown documentation for the type. | ### Children | Attribute | Type | Description | | --------- | ------------------------------------ | ----------------------- | | `child` | [`TypeNode`](../typeNodes/README.md) | The child of some node. | OR _This node has no children._ ## Functions ### `someNode(input)` Helper function that creates a `SomeNode` object from TODO. ```ts const node = someNode(TODO); ``` ## Examples ### Some example title ```ts someNode(TODO); // 0.01 USD => 0x01000000 // 10 USD => 0x03E80000 // 400.60 USD => 0x9C7C0000 ``` ================================================ FILE: packages/nodes/docs/contextualValueNodes/AccountBumpValueNode.md ================================================ # `AccountBumpValueNode` A node that refers to the seed bump of a PDA account. ## Attributes ### Data | Attribute | Type | Description | | --------- | ------------------------ | ------------------------ | | `kind` | `"accountBumpValueNode"` | The node discriminator. | | `name` | `CamelCaseString` | The name of the account. | ### Children _This node has no children._ ## Functions ### `accountBumpValueNode(name)` Helper function that creates a `AccountBumpValueNode` object from the account name. ```ts const node = accountBumpValueNode('associatedTokenAccount'); ``` ## Examples ### An instruction argument defaulting to the bump derivation of an instruction account ```ts instructionNode({ name: 'transfer', accounts: [ instructionAccountNode({ name: 'associatedTokenAccount', isSigner: false, isWritable: true, }), // ... ], arguments: [ instructionArgumentNode({ name: 'bump', type: numberTypeNode('u8'), defaultValue: accountBumpValueNode('associatedTokenAccount'), }), // ... ], }); ``` ================================================ FILE: packages/nodes/docs/contextualValueNodes/AccountValueNode.md ================================================ # `AccountValueNode` A node that refers to an account — e.g. an instruction account in the context of an instruction. ## Attributes ### Data | Attribute | Type | Description | | --------- | -------------------- | ------------------------ | | `kind` | `"accountValueNode"` | The node discriminator. | | `name` | `CamelCaseString` | The name of the account. | ### Children _This node has no children._ ## Functions ### `accountValueNode(name)` Helper function that creates a `AccountValueNode` object from the account name. ```ts const node = accountValueNode('mint'); ``` ## Examples ### An instruction account defaulting to another account ```ts instructionNode({ name: 'mint', accounts: [ instructionAccountNode({ name: 'payer', isSigner: true, isWritable: false, }), instructionAccountNode({ name: 'authority', isSigner: false, isWritable: true, defaultValue: accountValueNode('payer'), }), // ... ], }); ``` ================================================ FILE: packages/nodes/docs/contextualValueNodes/ArgumentValueNode.md ================================================ # `ArgumentValueNode` A node that refers to an argument — e.g. an instruction argument in the context of an instruction. ## Attributes ### Data | Attribute | Type | Description | | --------- | --------------------- | ------------------------- | | `kind` | `"argumentValueNode"` | The node discriminator. | | `name` | `CamelCaseString` | The name of the argument. | ### Children _This node has no children._ ## Functions ### `argumentValueNode(name)` Helper function that creates a `ArgumentValueNode` object from the argument name. ```ts const node = argumentValueNode('amount'); ``` ## Examples ### An instruction argument defaulting to another argument ```ts instructionNode({ name: 'mint', arguments: [ instructionArgumentNode({ name: 'amount', type: numberTypeNode('u64'), }), instructionArgumentNode({ name: 'amountToDelegate', type: numberTypeNode('u64'), defaultValue: argumentValueNode('amount'), }), // ... ], }); ``` ================================================ FILE: packages/nodes/docs/contextualValueNodes/ConditionalValueNode.md ================================================ # `ConditionalValueNode` A value node that differs based on a condition. ## Attributes ### Data | Attribute | Type | Description | | --------- | ------------------------ | ----------------------- | | `kind` | `"conditionalValueNode"` | The node discriminator. | ### Children | Attribute | Type | Description | | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | | `condition` | [`AccountValueNode`](./AccountValueNode.md) \| [`ArgumentValueNode`](./ArgumentValueNode.md) \| [`ResolverValueNode`](./ResolverValueNode.md) | The condition that must be met. If it is an argument or value node, the `value` attribute may be used to assert on a specific value. | | `value` | [`ValueNode`](../valueNodes/README.md) | (Optional) If provided, the `condition` must be equal to this value. Otherwise, the `condition` must simply exist. | | `ifTrue` | [`InstructionInputValueNode`](./InstructionInputValueNode.md) | (Optional) The value to use if the condition is true. | | `ifFalse` | [`InstructionInputValueNode`](./InstructionInputValueNode.md) | (Optional) The value to use if the condition is false. | ## Functions ### `conditionalValueNode(input)` Helper function that creates a `ConditionalValueNode` object from an input object. ```ts const node = conditionalValueNode({ condition: argumentValueNode('amount'), value: numberValueNode(0), ifTrue: accountValueNode('mint'), ifFalse: programIdValueNode(), }); ``` ## Examples ### An instruction account that defaults to another account if a condition is met ```ts instructionNode({ name: 'transfer', accounts: [ instructionAccountNode({ name: 'source', isSigner: false, isWritable: true, }), instructionAccountNode({ name: 'destination', isSigner: false, isWritable: true, isOptional: true, defaultValue: conditionalValueNode({ condition: argumentValueNode('amount'), value: numberValueNode(0), ifTrue: accountValueNode('source'), }), }), // ... ], arguments: [ instructionArgumentNode({ name: 'amount', type: numberTypeNode('u64'), }), ], }); ``` ================================================ FILE: packages/nodes/docs/contextualValueNodes/IdentityValueNode.md ================================================ # `IdentityValueNode` A node that represents the main wallet that should **own things**. For instance, in an web application, the identity would be the user's wallet; in a terminal, the identity would be the wallet identitied by `solana address`; etc. Note that a similar node exists for representing the main wallet that should **pay for things** — the [`PayerValueNode`](./PayerValueNode.md). In practice, the identity and the payer are often the same but allowing the program maintainer to offer this distinction can be useful should they be different. ## Attributes ### Data | Attribute | Type | Description | | --------- | --------------------- | ----------------------- | | `kind` | `"identityValueNode"` | The node discriminator. | ### Children _This node has no children._ ## Functions ### `identityValueNode()` Helper function that creates a `IdentityValueNode` object. ```ts const node = identityValueNode(); ``` ## Examples ### An instruction account defaulting to the identity value ```ts instructionNode({ name: 'transfer', accounts: [ instructionAccountNode({ name: 'authority', isSigner: true, isWritable: false, defaultValue: identityValueNode(), }), // ... ], }); ``` ================================================ FILE: packages/nodes/docs/contextualValueNodes/InstructionInputValueNode.md ================================================ # `InstructionInputValueNode` (abstract) The `InstructionInputValueNode` type helper represents all values that can be used as a default value for an instruction account or an instruction argument. Note that `InstructionInputValueNode` is a type alias and cannot be used directly as a node. Instead you may use one of the following nodes: - [`ContextualValueNode`](./README.md) (abstract) - [`ProgramLinkNode`](../linkNodes/ProgramLinkNode.md) - [`ValueNode`](../valueNodes/README.md) (abstract) ================================================ FILE: packages/nodes/docs/contextualValueNodes/PayerValueNode.md ================================================ # `PayerValueNode` A node that represents the main wallet that should **pay for things**. For instance, in an web application, the payer would be the user's wallet; in a terminal, the payer would be the wallet identitied by `solana address`; etc. Note that a similar node exists for representing the main wallet that should **own things** — the [`IdentityValueNode`](./IdentityValueNode.md). In practice, the payer and the identity are often the same but allowing the program maintainer to offer this distinction can be useful should they be different. ## Attributes ### Data | Attribute | Type | Description | | --------- | ------------------ | ----------------------- | | `kind` | `"payerValueNode"` | The node discriminator. | ### Children _This node has no children._ ## Functions ### `payerValueNode()` Helper function that creates a `PayerValueNode` object. ```ts const node = payerValueNode(); ``` ## Examples ### An instruction account defaulting to the payer value ```ts instructionNode({ name: 'transfer', accounts: [ instructionAccountNode({ name: 'payer', isSigner: true, isWritable: false, defaultValue: payerValueNode(), }), // ... ], }); ``` ================================================ FILE: packages/nodes/docs/contextualValueNodes/PdaSeedValueNode.md ================================================ # `PdaSeedValueNode` A node that represents the value of a variable PDA seed. ## Attributes ### Data | Attribute | Type | Description | | --------- | -------------------- | ------------------------------ | | `kind` | `"pdaSeedValueNode"` | The node discriminator. | | `name` | `CamelCaseString` | The name of the variable seed. | ### Children | Attribute | Type | Description | | --------- | -------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | | `value` | [`AccountValueNode`](./AccountValueNode.md) \| [`ArgumentValueNode`](./ArgumentValueNode.md) \| [`ValueNode`](../valueNodes/README.md) | The value of the variable PDA seed. This can be a simple `ValueNode` or a contextual value pointing to another account or argument. | ## Functions ### `pdaSeedValueNode(name, value)` Helper function that creates a `PdaSeedValueNode` object from the name of the variable seed and its value. ```ts const node = pdaSeedValueNode('mint', accountValueNode('mint')); ``` ================================================ FILE: packages/nodes/docs/contextualValueNodes/PdaValueNode.md ================================================ # `PdaValueNode` A node that represents a PDA value. It alone can be used to derive the PDA address. ## Attributes ### Data | Attribute | Type | Description | | --------- | ---------------- | ----------------------- | | `kind` | `"pdaValueNode"` | The node discriminator. | ### Children | Attribute | Type | Description | | --------- | -------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `pda` | [`PdaLinkNode`](../linkNodes/PdaLinkNode.md) \| [`PdaNode`](../PdaNode.md) | The PDA definition to use. It can either be a `PdaLinkNode` — therefore pointing to an existing PDA definition on the `ProgramNode` — or a direct `PdaNode` if we want to inline the PDA definition. | | `seeds` | [`PdaSeedValueNode`](./PdaSeedValueNode.md)[] | The values of all variable seeds in the PDA. | ## Functions ### `pdaValueNode(pda, seeds)` Helper function that creates a `PdaValueNode` object from a PDA definition and an array of seed values. When a `string` is provided as the `pda` definition, it is used as a `PdaLinkNode`. ```ts const node = pdaValueNode('associatedToken', [ pdaSeedValueNode('mint', publicKeyValueNode('G345gmp34svbGxyXuCvKVVHDbqJQ66y65vVrx7m7FmBE')), pdaSeedValueNode('owner', publicKeyValueNode('Nzgr9bYfMRq5768bHfXsXoPTnLWAXgQNosRBxK63jRH')), ]); ``` ## Examples ### A PDA value whose seeds point to other accounts ```ts pdaValueNode('associatedToken', [ pdaSeedValueNode('mint', accountValueNode('mint')), pdaSeedValueNode('owner', accountValueNode('authority')), ]); ``` ### A PDA value with an inlined PDA definition ```ts const inlinedPdaNode = pdaNode({ name: 'associatedToken', seeds: [ variablePdaSeedNode('mint', publicKeyTypeNode()), constantPdaSeedNode(publicKeyTypeNode(), publicKeyValueNode('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA')), variablePdaSeedNode('owner', publicKeyTypeNode()), ], }); pdaValueNode(inlinedPdaNode, [ pdaSeedValueNode('mint', accountValueNode('mint')), pdaSeedValueNode('owner', accountValueNode('authority')), ]); ``` ================================================ FILE: packages/nodes/docs/contextualValueNodes/ProgramIdValueNode.md ================================================ # `ProgramIdValueNode` A node that represents the public key of the current program. That is, the address of the `ProgramNode` from which this node descends. ## Attributes ### Data | Attribute | Type | Description | | --------- | ---------------------- | ----------------------- | | `kind` | `"programIdValueNode"` | The node discriminator. | ### Children _This node has no children._ ## Functions ### `programIdValueNode()` Helper function that creates a `ProgramIdValueNode` object. ```ts const node = programIdValueNode(); ``` ================================================ FILE: packages/nodes/docs/contextualValueNodes/README.md ================================================ # `ContextualValueNode` (abstract) The `ContextualValueNode` type helper represents all the available contextual value nodes. Note that `ContextualValueNode` is a type alias and cannot be used directly as a node. Instead you may use one of the following nodes: - [`AccountBumpValueNode`](./AccountBumpValueNode.md) - [`AccountValueNode`](./AccountValueNode.md) - [`ArgumentValueNode`](./ArgumentValueNode.md) - [`ConditionalValueNode`](./ConditionalValueNode.md) - [`IdentityValueNode`](./IdentityValueNode.md) - [`PayerValueNode`](./PayerValueNode.md) - [`PdaValueNode`](./PdaValueNode.md) - [`ProgramIdValueNode`](./ProgramIdValueNode.md) - [`ResolverValueNode`](./ResolverValueNode.md) ================================================ FILE: packages/nodes/docs/contextualValueNodes/ResolverValueNode.md ================================================ # `ResolverValueNode` A node that represents any custom value or logic described by some documentation. This node acts as a fallback node for any value or logic that cannot easily be described by the other nodes. Instead, the program maintainer can use this node to describe the value or logic in detail. Visitors that render code from Codama IDLs will treat these `ResolverValueNodes` as functions that can be injected into the generated code. ## Attributes ### Data | Attribute | Type | Description | | --------- | --------------------- | ---------------------------------------------------------------------------------------------------------------------- | | `kind` | `"resolverValueNode"` | The node discriminator. | | `name` | `CamelCaseString` | A unique name for the resolver. This will typically be the name of the function that the renderers will try to invoke. | | `docs` | `string[]` | Detailed Markdown documentation for the resolver. | ### Children | Attribute | Type | Description | | ----------- | ------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `dependsOn` | ([`AccountValueNode`](./AccountValueNode.md) \| [`ArgumentValueNode`](./ArgumentValueNode.md))[] | (Optional) The list of accounts or arguments that this custom value depends on. This is useful for code renderers to know in which order they should resolve default values. | ## Functions ### `resolverValueNode(name, options)` Helper function that creates a `ResolverValueNode` object from the resolver name and some options. ```ts const node = resolverValueNode('resolveCustomTokenProgram', { docs: [ 'If the mint account has more than 0 decimals and the ', 'delegated amount is greater than zero, than we use our ', 'own custom token program. Otherwise, we use Token 2022.', ], dependsOn: [accountValueNode('mint'), argumentValueNode('delegatedAmount')], }); ``` ================================================ FILE: packages/nodes/docs/countNodes/FixedCountNode.md ================================================ # `FixedCountNode` A node that represents a count strategy where **the number of items is known and fixed**. This enables nodes such as [`ArrayTypeNode`](../typeNodes/ArrayTypeNode.md) to represent arrays of a fixed length. ## Attributes ### Data | Attribute | Type | Description | | --------- | ------------------ | ------------------------- | | `kind` | `"fixedCountNode"` | The node discriminator. | | `value` | `number` | The fixed count of items. | ### Children _This node has no children._ ## Functions ### `fixedCountNode(value)` Helper function that creates a `FixedCountNode` object from a number. ```ts const node = fixedCountNode(42); ``` ## Examples ### An array of three public keys ```ts arrayTypeNode(publicKeyTypeNode(), fixedCountNode(3)); ``` ================================================ FILE: packages/nodes/docs/countNodes/PrefixedCountNode.md ================================================ # `PrefixedCountNode` A node that represents a count strategy where **the number of items is stored as a number prefix**. This enables nodes such as [`ArrayTypeNode`](../typeNodes/ArrayTypeNode.md) to represent arrays such that their length is stored as a prefix. ## Attributes ### Data | Attribute | Type | Description | | --------- | --------------------- | ----------------------- | | `kind` | `"prefixedCountNode"` | The node discriminator. | ### Children | Attribute | Type | Description | | --------- | ------------------------------------------------------------------------------------------------------ | --------------------------------------------- | | `prefix` | [`NestedTypeNode`](../typeNodes/NestedTypeNode.md)<[`NumberTypeNode`](../typeNodes/NumberTypeNode.md)> | The node that determines the number of items. | ## Functions ### `prefixedCountNode(prefix)` Helper function that creates a `PrefixedCountNode` object from a number node. ```ts const node = prefixedCountNode(numberTypeNode(u32)); ``` ## Examples ### An variable array of public keys prefixed with a u32 ```ts arrayTypeNode(publicKeyTypeNode(), prefixedCountNode(numberTypeNode(u32))); ``` ================================================ FILE: packages/nodes/docs/countNodes/README.md ================================================ # `CountNode` (abstract) The `CountNode` type helper represents all available strategies that determine the size of a collection. Note that `CountNode` is a type alias and cannot be used directly as a node. Instead you may use one of the following nodes: - [`FixedCountNode`](./FixedCountNode.md) - [`PrefixedCountNode`](./PrefixedCountNode.md) - [`RemainderCountNode`](./RemainderCountNode.md) ================================================ FILE: packages/nodes/docs/countNodes/RemainderCountNode.md ================================================ # `RemainderCountNode` A node that represents a count strategy where **the number of items is unknown and inferred by the remainder of the bytes**. When encoding, the items are encoded as-is without storing the total count. When decoding, items are decoded one by one until the end of the buffer is reached. This enables nodes such as [`ArrayTypeNode`](../typeNodes/ArrayTypeNode.md) to represent variable arrays at the end of buffers. ## Attributes ### Data | Attribute | Type | Description | | --------- | ---------------------- | ----------------------- | | `kind` | `"remainderCountNode"` | The node discriminator. | ### Children _This node has no children._ ## Functions ### `remainderCountNode()` Helper function that creates a `RemainderCountNode` object. ```ts const node = remainderCountNode(); ``` ## Examples ### A remainder array of public keys ```ts arrayTypeNode(publicKeyTypeNode(), remainderCountNode()); ``` ================================================ FILE: packages/nodes/docs/discriminatorNodes/ConstantDiscriminatorNode.md ================================================ # `ConstantDiscriminatorNode` This node represents a byte discrimination strategy where the data is **identified by a constant value** at a given offset. Discriminator nodes are used to distinguish between different types of accounts or instructions in a program. ## Attributes ### Data | Attribute | Type | Description | | --------- | ----------------------------- | ------------------------------------------------- | | `kind` | `"constantDiscriminatorNode"` | The node discriminator. | | `offset` | `number` | The byte at which the constant should be located. | ### Children | Attribute | Type | Description | | ---------- | -------------------------------------------------------- | -------------------------------------------- | | `constant` | [`ConstantValueNode`](./valueNodes/ConstantValueNode.md) | The constant value that identifies the data. | ## Functions ### `constantDiscriminatorNode(constant, offset?)` Helper function that creates a `ConstantDiscriminatorNode` object from a constant value node and an optional offset. ```ts const node = constantDiscriminatorNode(constantValueNodeFromString('utf8', 'Hello'), 64); ``` ## Examples ### An account distinguished by a u32 number equal to 42 at offset 0 ```ts accountNode({ discriminators: [constantDiscriminatorNode(constantValueNode(numberTypeNode('u32'), numberValueNode(42)))], // ... }); ``` ### An instruction disctinguished by an 8-byte hash at offset 0 ```ts instructionNode({ discriminators: [constantValueNodeFromBytes('base16', '0011223344556677')], // ... }); ``` ================================================ FILE: packages/nodes/docs/discriminatorNodes/FieldDiscriminatorNode.md ================================================ # `FieldDiscriminatorNode` This node represents a byte discrimination strategy where the data is **identified by the default value of a struct field** at a given offset. Discriminator nodes are used to distinguish between different types of accounts or instructions in a program. ## Attributes ### Data | Attribute | Type | Description | | --------- | -------------------------- | ---------------------------------------------------------------------------------------------------------------- | | `kind` | `"fieldDiscriminatorNode"` | The node discriminator. | | `field` | `CamelCaseString` | The name of the [`StructFieldTypeNode`](../typeNodes/StructFieldTypeNode.md) we should use to identify the data. | | `offset` | `number` | The byte at which the field should be located. | ### Children _This node has no children._ ## Functions ### `fieldDiscriminatorNode(field, offset?)` Helper function that creates a `FieldDiscriminatorNode` object from a field name and an optional offset. ```ts const node = fieldDiscriminatorNode('accountState', 64); ``` ## Examples ### An account distinguished by a u32 field at offset 0 ```ts accountNode({ data: structTypeNode([ structFieldTypeNode({ name: 'discriminator', type: numberTypeNode('u32'), defaultValue: numberValueNode(42), defaultValueStrategy: 'omitted', }), // ... ]), discriminators: [fieldDiscriminatorNode('discriminator')], // ... }); ``` ### An instruction disctinguished by an 8-byte argument at offset 0 ```ts instructionNode({ arguments: [ instructionArgumentNode({ name: 'discriminator', type: fixedSizeTypeNode(bytesTypeNode(), 8), defaultValue: bytesValueNode('base16', '0011223344556677'), defaultValueStrategy: 'omitted', }), // ... ], discriminators: [fieldDiscriminatorNode('discriminator')], // ... }); ``` ================================================ FILE: packages/nodes/docs/discriminatorNodes/README.md ================================================ # `DiscriminatorNode` (abstract) The `DiscriminatorNode` type helper represents all available strategies that help distinguish blocks of data — such as accounts and instructions. Note that `DiscriminatorNode` is a type alias and cannot be used directly as a node. Instead you may use one of the following nodes: - [`ConstantDiscriminatorNode`](./ConstantDiscriminatorNode.md) - [`FieldDiscriminatorNode`](./FieldDiscriminatorNode.md) - [`SizeDiscriminatorNode`](./SizeDiscriminatorNode.md) ================================================ FILE: packages/nodes/docs/discriminatorNodes/SizeDiscriminatorNode.md ================================================ # `SizeDiscriminatorNode` This node represents a byte discrimination strategy where the data is **identified by being equal to a given size**. Discriminator nodes are used to distinguish between different types of accounts or instructions in a program. ## Attributes ### Data | Attribute | Type | Description | | --------- | ------------------------- | ---------------------------------- | | `kind` | `"sizeDiscriminatorNode"` | The node discriminator. | | `size` | `number` | The size that identifies the data. | ### Children _This node has no children._ ## Functions ### `sizeDiscriminatorNode(size)` Helper function that creates a `SizeDiscriminatorNode` object from a size. ```ts const node = sizeDiscriminatorNode(165); ``` ## Examples ### An account distinguished by its size being equal to 42 ```ts accountNode({ discriminators: [sizeDiscriminatorNode(42)], // ... }); ``` ### An instruction disctinguished by its size being equal to 42 ```ts instructionNode({ discriminators: [sizeDiscriminatorNode(42)], // ... }); ``` ================================================ FILE: packages/nodes/docs/linkNodes/AccountLinkNode.md ================================================ # `AccountLinkNode` This node represents a reference to an existing [`AccountNode`](../AccountNode.md) in the Codama IDL. ## Attributes ### Data | Attribute | Type | Description | | --------- | ------------------- | ----------------------------------------------------------------------- | | `kind` | `"accountLinkNode"` | The node discriminator. | | `name` | `CamelCaseString` | The name of the [`AccountNode`](../AccountNode.md) we are referring to. | ### Children | Attribute | Type | Description | | --------- | ----------------------------------------- | --------------------------------------------------------------------------------------------------------------- | | `program` | [`ProgramLinkNode`](./ProgramLinkNode.md) | (Optional) The program associated with the linked account. Default to using the program we are currently under. | ## Functions ### `accountLinkNode(name, program?)` Helper function that creates an `AccountLinkNode` object from the name of the `AccountNode` we are referring to. If the account is from another program, the `program` parameter must be provided as either a `string` or a `ProgramLinkNode`. ```ts const node = accountLinkNode('myAccount'); const nodeFromAnotherProgram = accountLinkNode('myAccount', 'myOtherProgram'); ``` ================================================ FILE: packages/nodes/docs/linkNodes/DefinedTypeLinkNode.md ================================================ # `DefinedTypeLinkNode` This node represents a reference to an existing [`DefinedTypeNode`](../DefinedTypeNode.md) in the Codama IDL. ## Attributes ### Data | Attribute | Type | Description | | --------- | ----------------------- | ------------------------------------------------------------------------------- | | `kind` | `"definedTypeLinkNode"` | The node discriminator. | | `name` | `CamelCaseString` | The name of the [`DefinedTypeNode`](../DefinedTypeNode.md) we are referring to. | ### Children | Attribute | Type | Description | | --------- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------ | | `program` | [`ProgramLinkNode`](./ProgramLinkNode.md) | (Optional) The program associated with the linked type. Default to using the program we are currently under. | ## Functions ### `definedTypeLinkNode(name, program?)` Helper function that creates a `DefinedTypeLinkNode` object from the name of the `DefinedTypeNode` we are referring to. If the defined type is from another program, the `program` parameter must be provided as either a `string` or a `ProgramLinkNode`. ```ts const node = definedTypeLinkNode('myDefinedType'); const nodeFromAnotherProgram = definedTypeLinkNode('myDefinedType', 'myOtherProgram'); ``` ================================================ FILE: packages/nodes/docs/linkNodes/InstructionAccountLinkNode.md ================================================ # `InstructionAccountLinkNode` This node represents a reference to an existing [`InstructionAccountNode`](../InstructionAccountNode.md) in the Codama IDL. ## Attributes ### Data | Attribute | Type | Description | | --------- | ------------------------------ | --------------------------------------------------------------------------------------------- | | `kind` | `"instructionAccountLinkNode"` | The node discriminator. | | `name` | `CamelCaseString` | The name of the [`InstructionAccountNode`](../InstructionAccountNode.md) we are referring to. | ### Children | Attribute | Type | Description | | ------------- | ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `instruction` | [`InstructionLinkNode`](./InstructionLinkNode.md) | (Optional) The instruction associated with the linked account. Default to using the instruction we are currently under. Note that the instruction itself can point to a different program is needed. | ## Functions ### `instructionAccountLinkNode(name, instruction?)` Helper function that creates an `InstructionAccountLinkNode` object from the name of the `InstructionAccountNode` we are referring to. If the account is from another instruction, the `instruction` parameter must be provided as either a `string` or a `InstructionLinkNode`. When providing an `InstructionLinkNode`, we can also provide a `ProgramLinkNode` to point to a different program. ```ts // Links to an account in the current instruction. const node = instructionAccountLinkNode('myAccount'); // Links to an account in another instruction but within the same program. const nodeFromAnotherInstruction = instructionAccountLinkNode('myAccount', 'myOtherInstruction'); // Links to an account in another instruction from another program. const nodeFromAnotherProgram = instructionAccountLinkNode( 'myAccount', instructionLinkNode('myOtherInstruction', 'myOtherProgram'), ); ``` ================================================ FILE: packages/nodes/docs/linkNodes/InstructionArgumentLinkNode.md ================================================ # `InstructionArgumentLinkNode` This node represents a reference to an existing [`InstructionArgumentNode`](../InstructionArgumentNode.md) in the Codama IDL. ## Attributes ### Data | Attribute | Type | Description | | --------- | ------------------------------- | ----------------------------------------------------------------------------------------------- | | `kind` | `"instructionArgumentLinkNode"` | The node discriminator. | | `name` | `CamelCaseString` | The name of the [`InstructionArgumentNode`](../InstructionArgumentNode.md) we are referring to. | ### Children | Attribute | Type | Description | | ------------- | ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `instruction` | [`InstructionLinkNode`](./InstructionLinkNode.md) | (Optional) The instruction associated with the linked argument. Default to using the instruction we are currently under. Note that the instruction itself can point to a different program is needed. | ## Functions ### `instructionArgumentLinkNode(name, instruction?)` Helper function that creates an `InstructionArgumentLinkNode` object from the name of the `InstructionArgumentNode` we are referring to. If the argument is from another instruction, the `instruction` parameter must be provided as either a `string` or a `InstructionLinkNode`. When providing an `InstructionLinkNode`, we can also provide a `ProgramLinkNode` to point to a different program. ```ts // Links to an argument in the current instruction. const node = instructionArgumentLinkNode('myArgument'); // Links to an argument in another instruction but within the same program. const nodeFromAnotherInstruction = instructionArgumentLinkNode('myArgument', 'myOtherInstruction'); // Links to an argument in another instruction from another program. const nodeFromAnotherProgram = instructionArgumentLinkNode( 'myArgument', instructionLinkNode('myOtherInstruction', 'myOtherProgram'), ); ``` ================================================ FILE: packages/nodes/docs/linkNodes/InstructionLinkNode.md ================================================ # `InstructionLinkNode` This node represents a reference to an existing [`InstructionNode`](../InstructionNode.md) in the Codama IDL. ## Attributes ### Data | Attribute | Type | Description | | --------- | ----------------------- | ------------------------------------------------------------------------------- | | `kind` | `"instructionLinkNode"` | The node discriminator. | | `name` | `CamelCaseString` | The name of the [`InstructionNode`](../InstructionNode.md) we are referring to. | ### Children | Attribute | Type | Description | | --------- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | | `program` | [`ProgramLinkNode`](./ProgramLinkNode.md) | (Optional) The program associated with the linked instruction. Default to using the program we are currently under. | ## Functions ### `instructionLinkNode(name, program?)` Helper function that creates an `InstructionLinkNode` object from the name of the `InstructionNode` we are referring to. If the instruction is from another program, the `program` parameter must be provided as either a `string` or a `ProgramLinkNode`. ```ts const node = instructionLinkNode('myInstruction'); const nodeFromAnotherProgram = instructionLinkNode('myInstruction', 'myOtherProgram'); ``` ================================================ FILE: packages/nodes/docs/linkNodes/PdaLinkNode.md ================================================ # `PdaLinkNode` This node represents a reference to an existing [`PdaNode`](../PdaNode.md) in the Codama IDL. ## Attributes ### Data | Attribute | Type | Description | | --------- | ----------------- | --------------------------------------------------------------- | | `kind` | `"pdaLinkNode"` | The node discriminator. | | `name` | `CamelCaseString` | The name of the [`PdaNode`](../PdaNode.md) we are referring to. | ### Children | Attribute | Type | Description | | --------- | ----------------------------------------- | ----------------------------------------------------------------------------------------------------------- | | `program` | [`ProgramLinkNode`](./ProgramLinkNode.md) | (Optional) The program associated with the linked PDA. Default to using the program we are currently under. | ## Functions ### `pdaLinkNode(name, program?)` Helper function that creates a `PdaLinkNode` object from the name of the `PdaNode` we are referring to. If the PDA is from another program, the `program` parameter must be provided as either a `string` or a `ProgramLinkNode`. ```ts const node = pdaLinkNode('myPda'); const nodeFromAnotherProgram = pdaLinkNode('myPda', 'myOtherProgram'); ``` ================================================ FILE: packages/nodes/docs/linkNodes/ProgramLinkNode.md ================================================ # `ProgramLinkNode` This node represents a reference to an existing [`ProgramNode`](../ProgramNode.md) in the Codama IDL. ## Attributes ### Data | Attribute | Type | Description | | --------- | ------------------- | ----------------------------------------------------------------------- | | `kind` | `"programLinkNode"` | The node discriminator. | | `name` | `CamelCaseString` | The name of the [`ProgramNode`](../ProgramNode.md) we are referring to. | ### Children _This node has no children._ ## Functions ### `programLinkNode(name)` Helper function that creates a `ProgramLinkNode` object from the name of the `ProgramNode` we are referring to. ```ts const node = programLinkNode('myProgram'); ``` ================================================ FILE: packages/nodes/docs/linkNodes/README.md ================================================ # `LinkNode` (abstract) The `LinkNode` type helper represents all nodes that link to other nodes. Note that `LinkNode` is a type alias and cannot be used directly as a node. Instead you may use one of the following nodes: - [`AccountLinkNode`](./AccountLinkNode.md) - [`DefinedTypeLinkNode`](./DefinedTypeLinkNode.md) - [`InstructionAccountLinkNode`](./InstructionAccountLinkNode.md) - [`InstructionArgumentLinkNode`](./InstructionArgumentLinkNode.md) - [`InstructionLinkNode`](./InstructionLinkNode.md) - [`PdaLinkNode`](./PdaLinkNode.md) - [`ProgramLinkNode`](./ProgramLinkNode.md) ================================================ FILE: packages/nodes/docs/pdaSeedNodes/ConstantPdaSeedNode.md ================================================ # `ConstantPdaSeedNode` This node represents a constant seed for a program-derived address (PDA). ## Attributes ### Data | Attribute | Type | Description | | --------- | ----------------------- | ----------------------- | | `kind` | `"constantPdaSeedNode"` | The node discriminator. | ### Children | Attribute | Type | Description | | --------- | --------------------------------------------------------------------------------------------------------------- | ------------------------------- | | `type` | [`TypeNode`](../typeNodes/README.md) | The type of the constant seed. | | `value` | [`ValueNode`](../valueNodes/README.md) \| [`ProgramIdValueNode`](../contextualValueNodes/ProgramIdValueNode.md) | The value of the constant seed. | ## Functions ### `constantPdaSeedNode(type, value)` Helper function that creates a `ConstantPdaSeedNode` object from a type node and a value node. ```ts const node = constantPdaSeedNode(numberTypeNode('u32'), numberValueNode(42)); ``` ### `constantPdaSeedNodeFromString(encoding, data)` Helper function that creates a `ConstantPdaSeedNode` object of type `StringTypeNode` from an encoding and a string of data. ```ts constantPdaSeedNodeFromString('utf8', 'Hello'); // Equivalent to: constantPdaSeedNode(stringTypeNode('utf8'), stringValueNode('Hello')); ``` ### `constantValueNodeFromBytes(encoding, data)` Helper function that creates a `ConstantValueNode` object of type `BytesTypeNode` from an encoding and a string of data. ```ts constantValueNodeFromBytes('base16', 'FF99CC'); // Equivalent to: constantValueNode(bytesTypeNode(), bytesValueNode('base16', 'FF99CC')); ``` ## Examples ### A PDA node with a UTF-8 constant seed ```ts pdaNode({ name: 'tickets', seeds: [constantPdaSeedNodeFromString('utf8', 'tickets')], }); ``` ================================================ FILE: packages/nodes/docs/pdaSeedNodes/README.md ================================================ # `PdaSeedNode` (abstract) The `PdaSeedNode` type helper represents all ways to define a PDA seed. Note that `PdaSeedNode` is a type alias and cannot be used directly as a node. Instead you may use one of the following nodes: - [`ConstantPdaSeedNode`](./ConstantPdaSeedNode.md) - [`VariablePdaSeedNode`](./VariablePdaSeedNode.md) ================================================ FILE: packages/nodes/docs/pdaSeedNodes/VariablePdaSeedNode.md ================================================ # `VariablePdaSeedNode` This node represents a variable seed for a program-derived address (PDA). It is characterized by a name and a type. ## Attributes ### Data | Attribute | Type | Description | | --------- | ----------------------- | --------------------------------------------- | | `kind` | `"variablePdaSeedNode"` | The node discriminator. | | `name` | `CamelCaseString` | The name of the variable seed. | | `docs` | `string[]` | Markdown documentation for the variable seed. | ### Children | Attribute | Type | Description | | --------- | ------------------------------------ | ------------------------------ | | `type` | [`TypeNode`](../typeNodes/README.md) | The type of the variable seed. | ## Functions ### `variablePdaSeedNode(name, type, docs?)` Helper function that creates a `VariablePdaSeedNode` object from a name, a type node and optional documentation. ```ts const node = variablePdaSeedNode('amount', numberTypeNode('u32')); ``` ## Examples ### A PDA node with a public key variable seed ```ts pdaNode({ name: 'ticket', seeds: [variablePdaSeedNode('authority', publicKeyTypeNode())], }); ``` ================================================ FILE: packages/nodes/docs/typeNodes/AmountTypeNode.md ================================================ # `AmountTypeNode` A node that wraps a [`NumberTypeNode`](./NumberTypeNode.md) to provide additional context such as its unit and decimal places. ## Attributes ### Data | Attribute | Type | Description | | ---------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `kind` | `"amountTypeNode"` | The node discriminator. | | `decimals` | `number` | The number of decimal places the wrapped integer has. For instance, if the wrapper number is a `12345` and `decimals === 2`, then the amount should be interpreted as `123.45`. This is particularly useful to represent financial values as floating points are notoriously unsafe for that purpose. | | `unit` | `string` | (Optional) The unit of the amount — e.g. `"USD"` or `"%"`. | ### Children | Attribute | Type | Description | | --------- | -------------------------------------------------------------------------------- | ------------------------ | | `number` | [`NestedTypeNode`](./NestedTypeNode.md)<[`NumberTypeNode`](./NumberTypeNode.md)> | The number node to wrap. | ## Functions ### `amountTypeNode(number, decimals, unit?)` Helper function that creates a `AmountTypeNode` object from a `NumberTypeNode`, a number of decimals and an optional unit. ```ts const node = amountTypeNode(numberTypeNode('u64'), 2, 'USD'); const nodeWithoutUnits = amountTypeNode(numberTypeNode('u16'), 2); ``` ## Examples ### 2-decimals USD amount ```ts amountTypeNode(numberTypeNode('u32'), 2, 'USD'); // 0.01 USD => 0x01000000 // 10 USD => 0xE8030000 // 400.60 USD => 0x7C9C0000 ``` ================================================ FILE: packages/nodes/docs/typeNodes/ArrayTypeNode.md ================================================ # `ArrayTypeNode` A node that represents an array of items. The type of each item is defined by the `item` child node and the length of the array is determined by the `count` child node. ## Attributes ### Data | Attribute | Type | Description | | --------- | ----------------- | ----------------------- | | `kind` | `"arrayTypeNode"` | The node discriminator. | ### Children | Attribute | Type | Description | | --------- | -------------------------------------- | ------------------------------------------------ | | `item` | [`TypeNode`](./README.md) | The type of each item in the array. | | `count` | [`CountNode`](../countNodes/README.md) | The strategy to determine the size of the array. | ## Functions ### `arrayTypeNode(item, count)` Helper function that creates a `ArrayTypeNode` object from a `TypeNode` and a `CountNode`. ```ts const node = arrayTypeNode(publicKeyTypeNode(), prefixedCountNode(numberTypeNode('u32'))); ``` ## Examples ### u32 prefixed array of u8 numbers ![Diagram](https://github.com/codama-idl/codama/assets/3642397/1bbd3ecb-e06a-42fa-94a7-74c9302286e6) ```ts arrayTypeNode(numberTypeNode('u8'), prefixedCountNode(numberTypeNode('u32'))); // [1, 2, 3] => 0x03000000010203 ``` ================================================ FILE: packages/nodes/docs/typeNodes/BooleanTypeNode.md ================================================ # `BooleanTypeNode` A node that represents a boolean value using a `NumberTypeNode`. If the number is `1`, then the boolean is `true`, otherwise it is `false`. ## Attributes ### Data | Attribute | Type | Description | | --------- | ------------------- | ----------------------- | | `kind` | `"booleanTypeNode"` | The node discriminator. | ### Children | Attribute | Type | Description | | --------- | -------------------------------------------------------------------------------- | ---------------------------------------------- | | `size` | [`NestedTypeNode`](./NestedTypeNode.md)<[`NumberTypeNode`](./NumberTypeNode.md)> | The number node used to represent the boolean. | ## Functions ### `booleanTypeNode(size?)` Helper function that creates a `BooleanTypeNode` object from a `NumberTypeNode` (defaulting to `u8` if not provided). ```ts const node = booleanTypeNode(numberTypeNode('u32')); const implicitU8Node = booleanTypeNode(); // u8 by default ``` ## Examples ### u8 booleans ```ts booleanTypeNode(); // true => 0x01 // false => 0x00 ``` ### u32 booleans ```ts booleanTypeNode(numberTypeNode('u32')); // true => 0x01000000 // false => 0x00000000 ``` ================================================ FILE: packages/nodes/docs/typeNodes/BytesTypeNode.md ================================================ # `BytesTypeNode` A node that represents data as raw bytes. This can be useful for representing data that doesn't have a specific type or structure. It can also be shaped in size using nodes such as the [`SizePrefixTypeNode`](./SizePrefixTypeNode.md) or the [`FixedSizeTypeNode`](./FixedSizeTypeNode.md). ## Attributes ### Data | Attribute | Type | Description | | --------- | ----------------- | ----------------------- | | `kind` | `"bytesTypeNode"` | The node discriminator. | ### Children _This node has no children._ ## Functions ### `bytesTypeNode()` Helper function that creates a `BytesTypeNode` object. ```ts const node = bytesTypeNode(); ``` ================================================ FILE: packages/nodes/docs/typeNodes/DateTimeTypeNode.md ================================================ # `DateTimeTypeNode` A node that wraps a [`NumberTypeNode`](./NumberTypeNode.md) to make it a datetime such that the number represents the number of seconds since the Unix epoch. ## Attributes ### Data | Attribute | Type | Description | | --------- | -------------------- | ----------------------- | | `kind` | `"dateTimeTypeNode"` | The node discriminator. | ### Children | Attribute | Type | Description | | --------- | -------------------------------------------------------------------------------- | ------------------------ | | `number` | [`NestedTypeNode`](./NestedTypeNode.md)<[`NumberTypeNode`](./NumberTypeNode.md)> | The number node to wrap. | ## Functions ### `dateTimeTypeNode(number)` Helper function that creates a `DateTimeTypeNode` object from a `NumberTypeNode`. ```ts const node = dateTimeTypeNode(numberTypeNode('u64')); ``` ## Examples ### u64 unix datetime ```ts dateTimeTypeNode(numberTypeNode('u64')); // 2024-06-27T14:57:56Z => 0x667D7DF400000000 ``` ================================================ FILE: packages/nodes/docs/typeNodes/EnumEmptyVariantTypeNode.md ================================================ # `EnumEmptyVariantTypeNode` A node that defines an enum variant with no data. ## Attributes ### Data | Attribute | Type | Description | | --------------- | ---------------------------- | --------------------------------------------------------------------------------------------------------------- | | `kind` | `"enumEmptyVariantTypeNode"` | The node discriminator. | | `name` | `CamelCaseString` | The name of the enum variant. | | `discriminator` | `number` | (Optional) The variant's discriminator value. Defaults to the index of the variant in the enum (starting at 0). | ### Children _This node has no children._ ## Functions ### `enumEmptyVariantTypeNode(name)` Helper function that creates a `EnumEmptyVariantTypeNode` object from its name. ```ts const node = enumEmptyVariantTypeNode('myVariantName'); ``` ================================================ FILE: packages/nodes/docs/typeNodes/EnumStructVariantTypeNode.md ================================================ # `EnumStructVariantTypeNode` A node that defines an enum variant with a struct data type. ## Attributes ### Data | Attribute | Type | Description | | --------------- | ----------------------------- | --------------------------------------------------------------------------------------------------------------- | | `kind` | `"enumStructVariantTypeNode"` | The node discriminator. | | `name` | `CamelCaseString` | The name of the enum variant. | | `discriminator` | `number` | (Optional) The variant's discriminator value. Defaults to the index of the variant in the enum (starting at 0). | ### Children | Attribute | Type | Description | | --------- | -------------------------------------------------------------------------------- | ------------------------------------- | | `struct` | [`NestedTypeNode`](./NestedTypeNode.md)<[`StructTypeNode`](./StructTypeNode.md)> | The struct data type for the variant. | ## Functions ### `enumStructVariantTypeNode(name, struct, discriminator?)` Helper function that creates a `EnumStructVariantTypeNode` object from its name and data. ```ts const node = enumStructVariantTypeNode( 'coordinates', structTypeNode([ structFieldTypeNode({ name: 'x', type: numberTypeNode('u32') }), structFieldTypeNode({ name: 'y', type: numberTypeNode('u32') }), ]), ); ``` ================================================ FILE: packages/nodes/docs/typeNodes/EnumTupleVariantTypeNode.md ================================================ # `EnumTupleVariantTypeNode` A node that defines an enum variant with a tuple data type. ## Attributes ### Data | Attribute | Type | Description | | --------------- | ---------------------------- | --------------------------------------------------------------------------------------------------------------- | | `kind` | `"enumTupleVariantTypeNode"` | The node discriminator. | | `name` | `CamelCaseString` | The name of the enum variant. | | `discriminator` | `number` | (Optional) The variant's discriminator value. Defaults to the index of the variant in the enum (starting at 0). | ### Children | Attribute | Type | Description | | --------- | ------------------------------------------------------------------------------ | ------------------------------------ | | `tuple` | [`NestedTypeNode`](./NestedTypeNode.md)<[`TupleTypeNode`](./TupleTypeNode.md)> | The tuple data type for the variant. | ## Functions ### `enumTupleVariantTypeNode(name, tuple, discriminator?)` Helper function that creates a `EnumTupleVariantTypeNode` object from its name and data. ```ts const node = enumTupleVariantTypeNode('coordinates', tupleTypeNode([numberTypeNode('u32'), numberTypeNode('u32')])); ``` ================================================ FILE: packages/nodes/docs/typeNodes/EnumTypeNode.md ================================================ # `EnumTypeNode` A node that can represent data in various states using enum variants. Each variant has a unique name and can have associated data. ## Attributes ### Data | Attribute | Type | Description | | --------- | ---------------- | ----------------------- | | `kind` | `"enumTypeNode"` | The node discriminator. | ### Children | Attribute | Type | Description | | ---------- | -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `variants` | [`EnumVariantTypeNode`](./EnumVariantTypeNode)[] | All variants the node can represent. | | `size` | [`NestedTypeNode`](./NestedTypeNode.md)<[`NumberTypeNode`](./NumberTypeNode.md)> | The size of the enum discriminator as a `NumberTypeNode`. This number will prepend the serialised enum variant in order to identify which variant was selected. By default, the index of the variant (starting at 0) is used as a variant discriminator. However, each variant can optionally provide their own custom discriminator number. | ## Functions ### `enumTypeNode(variants, options?)` Helper function that creates a `EnumTypeNode` object from an array of `EnumVariantTypeNode` objects and an optional `size` attribute that can be passed in the `options` object as a second argument. ```ts const node = enumTypeNode(variants); const nodeWithU32Discriminator = enumTypeNode(variants, { size: numberTypeNode('u32') }); ``` ## Examples ### Enum with u8 discriminator ```ts enumTypeNode([ enumEmptyVariantTypeNode('flip'), enumTupleVariantTypeNode('rotate', tupleTypeNode([numberTypeNode('u32')])), enumStructVariantTypeNode( 'move', structTypeNode([ structFieldTypeNode({ name: 'x', type: numberTypeNode('u16') }), structFieldTypeNode({ name: 'y', type: numberTypeNode('u16') }), ]), ), ]); // Flip => 0x00 // Rotate (42) => 0x012A000000 // Move { x: 1, y: 2 } => 0x0201000200 ``` ================================================ FILE: packages/nodes/docs/typeNodes/EnumVariantTypeNode.md ================================================ # `EnumVariantTypeNode` (abstract) The `EnumVariantTypeNode` type helper represents any of the available enum variant types. Note that it cannot be used directly as a node. Instead you may use one of the following types: - [`EnumEmptyVariantTypeNode`](./EnumEmptyVariantTypeNode.md) - [`EnumStructVariantTypeNode`](./EnumStructVariantTypeNode.md) - [`EnumTupleVariantTypeNode`](./EnumTupleVariantTypeNode.md) ================================================ FILE: packages/nodes/docs/typeNodes/FixedSizeTypeNode.md ================================================ # `FixedSizeTypeNode` A node that takes another type node as a child and fixes its byte length to the provided size. It will pad or truncate the data to match the fixed size. This node can be used to create [`NestedTypeNodes`](./NestedTypeNode.md). ## Attributes ### Data | Attribute | Type | Description | | --------- | --------------------- | ---------------------------------- | | `kind` | `"fixedSizeTypeNode"` | The node discriminator. | | `size` | `number` | The fixed byte length of the type. | ### Children | Attribute | Type | Description | | --------- | ------------------------- | --------------------------------------------------------- | | `type` | [`TypeNode`](./README.md) | The node type from which the byte length should be fixed. | ## Functions ### `fixedSizeTypeNode(type, size)` Helper function that creates a `FixedSizeTypeNode` object from a type node and a fixed byte length. ```ts const node = fixedSizeTypeNode(stringTypeNode('utf8'), 32); ``` ## Examples ### Fixed UTF-8 strings ```ts fixedSizeTypeNode(stringTypeNode('utf8'), 10); // Hello => 0x48656C6C6F0000000000 ``` ### Fixed byte arrays ```ts fixedSizeTypeNode(bytesTypeNode(), 4); // [1, 2] => 0x01020000 // [1, 2, 3, 4, 5] => 0x01020304 ``` ================================================ FILE: packages/nodes/docs/typeNodes/HiddenPrefixTypeNode.md ================================================ # `HiddenPrefixTypeNode` A node that wraps a type node and whilst silently consuming a prefix of constant values. When encoding, the constant values are written before the child node. When decoding, the prefixed constant values are consumed and checked against the expected values before being discarded. This node can be used to create [`NestedTypeNodes`](./NestedTypeNode.md). ## Attributes ### Data | Attribute | Type | Description | | --------- | ------------------------ | ----------------------- | | `kind` | `"hiddenPrefixTypeNode"` | The node discriminator. | ### Children | Attribute | Type | Description | | --------- | ---------------------------------------------------------- | ------------------------------------------ | | `type` | [`TypeNode`](./README.md) | The type node to wrap. | | `prefix` | [`ConstantValueNode`](./valueNodes/ConstantValueNode.md)[] | The array of constant prefixes to consume. | ## Functions ### `hiddenPrefixTypeNode(type, prefix)` Helper function that creates a `HiddenPrefixTypeNode` object from a type node and an array of constant value nodes. ```ts const node = hiddenPrefixTypeNode(numberTypeNode('u32'), [ constantValueNode(bytesTypeNode(), bytesValueNode('base16', 'ffff')), ]); ``` ## Examples ### A number prefixed with 0xFFFF ```ts hiddenPrefixTypeNode(numberTypeNode('u32'), [constantValueNode(bytesTypeNode(), bytesValueNode('base16', 'ffff'))]); // 42 => 0xFFFF2A000000 ``` ### A fixed UTF-8 string prefixed with "Hello" ```ts hiddenPrefixTypeNode(fixedSizeTypeNode(stringTypeNode('utf8'), 10), [ constantValueNode(stringTypeNode('utf8'), stringValueNode('Hello')), ]); // World => 0x48656C6C6F576F726C640000000000 ``` ================================================ FILE: packages/nodes/docs/typeNodes/HiddenSuffixTypeNode.md ================================================ # `HiddenSuffixTypeNode` A node that wraps a type node and whilst silently consuming a suffix of constant values. When encoding, the constant values are written after the child node. When decoding, the suffixed constant values are consumed and checked against the expected values before being discarded. This node can be used to create [`NestedTypeNodes`](./NestedTypeNode.md). ## Attributes ### Data | Attribute | Type | Description | | --------- | ------------------------ | ----------------------- | | `kind` | `"hiddenSuffixTypeNode"` | The node discriminator. | ### Children | Attribute | Type | Description | | --------- | ---------------------------------------------------------- | ------------------------------------------ | | `type` | [`TypeNode`](./README.md) | The type node to wrap. | | `suffix` | [`ConstantValueNode`](./valueNodes/ConstantValueNode.md)[] | The array of constant suffixes to consume. | ## Functions ### `hiddenSuffixTypeNode(type, suffix)` Helper function that creates a `HiddenSuffixTypeNode` object from a type node and an array of constant value nodes. ```ts const node = hiddenSuffixTypeNode(numberTypeNode('u32'), [ constantValueNode(bytesTypeNode(), bytesValueNode('base16', 'ffff')), ]); ``` ## Examples ### A number suffixed with 0xFFFF ```ts hiddenSuffixTypeNode(numberTypeNode('u32'), [constantValueNode(bytesTypeNode(), bytesValueNode('base16', 'ffff'))]); // 42 => 0x2A000000FFFF ``` ### A fixed UTF-8 string suffixed with "Hello" ```ts hiddenSuffixTypeNode(fixedSizeTypeNode(stringTypeNode('utf8'), 10), [ constantValueNode(stringTypeNode('utf8'), stringValueNode('Hello')), ]); // World => 0x576F726C64000000000048656c6c6F ``` ================================================ FILE: packages/nodes/docs/typeNodes/MapTypeNode.md ================================================ # `MapTypeNode` A node that represents key/value pairs. A key `TypeNode` and a value `TypeNode` are used to define every keys and values in the map. Map entries are encoded one after the other, with the key first followed by the value — e.g. Key A, Value A, Key B, Value B, etc. The number of entries in the map is determined by the `count` child node. ## Attributes ### Data | Attribute | Type | Description | | --------- | --------------- | ----------------------- | | `kind` | `"mapTypeNode"` | The node discriminator. | ### Children | Attribute | Type | Description | | --------- | -------------------------------------- | ----------------------------------------- | | `key` | [`TypeNode`](./README.md) | The type of every key in the map. | | `value` | [`TypeNode`](./README.md) | The type of every value in the map. | | `count` | [`CountNode`](../countNodes/README.md) | The strategy to determine the map length. | ## Functions ### `mapTypeNode(key, value, count)` Helper function that creates a `MapTypeNode` object from a key `TypeNode`, a value `TypeNode` and a `CountNode`. ```ts const node = mapTypeNode(publicKeyTypeNode(), numberTypeNode('u32'), prefixedCountNode(numberTypeNode('u32'))); ``` ## Examples ### An histogram that counts letters ```ts mapTypeNode( fixedSizeTypeNode(stringTypeNode('utf8'), 1), // Key: Single UTF-8 character. numberTypeNode('u16'), // Value: 16-bit unsigned integer. prefixedCountNode(numberTypeNode('u8')), // Count: map length is prefixed with a u8. ); // { A: 42, B: 1, C: 16 } => 0x03000000412A00420100431000 ``` ================================================ FILE: packages/nodes/docs/typeNodes/NestedTypeNode.md ================================================ # `NestedTypeNode` (helper) The `NestedTypeNode` type is a generic helper type that allows us to define nested requirements for a child node. The requirement `NestedTypeNode` – where `T` is any `TypeNode` — tells us that the child node may be wrapped however they want but, eventually, we should end up with a `T` type node. For instance, say we have the following requirement: `NestedTypeNode`. This requirement can be fulfilled by a simple `StringTypeNode` but it can also be fulfilled by a `FixedSizeTypeNode` that wraps a `StringTypeNode` and fixes its byte length, since the end result is still a `StringTypeNode`. We can even go further and nest multiple wrappers, as long as the final node is a `StringTypeNode` — e.g. `HiddenPrefixTypeNode>>`. ## Available wrappers Therefore, when encountering a `NestedTypeNode` requirement, we can either provide the type `T` itself or any nested combination of nodes that includes the following wrappers: - [`FixedSizeTypeNode`](./FixedSizeTypeNode.md) - [`HiddenPrefixTypeNode`](./HiddenPrefixTypeNode.md) - [`HiddenSuffixTypeNode`](./HiddenSuffixTypeNode.md) - [`PostOffsetTypeNode`](./PostOffsetTypeNode.md) - [`PreOffsetTypeNode`](./PreOffsetTypeNode.md) - [`SentinelTypeNode`](./SentinelTypeNode.md) - [`SizePrefixTypeNode`](./SizePrefixTypeNode.md) ## Functions Some helper functions are available to work with `NestedTypeNodes`. ### `resolveNestedTypeNode(nestedTypeNode)` This function returns the final `TypeNode` of a nested type node. In other words, given a `NestedTypeNode`, it will return the `T`. ```ts const nestedNode = fixedSizeTypeNode(stringTypeNode('utf8'), 10); const resolvedNode = resolveNestedTypeNode(nestedNode); // ^ stringTypeNode('utf8') ``` ### `transformNestedTypeNode(nestedTypeNode, map)` This function transforms the final `TypeNode` of a nested type node from a provided function. In other words, given a `NestedTypeNode` and a `T => U` function, it will return a `NestedTypeNode`. ```ts const nestedNode = fixedSizeTypeNode(stringTypeNode('utf8'), 10); const transformedNode = transformNestedTypeNode(nestedNode, () => stringTypeNode('base64')); // ^ fixedSizeTypeNode(stringTypeNode('base64'), 10); ``` ### `isNestedTypeNode(node, kind)` This function checks if the final `TypeNode` of a nested type node is of the given kind or kinds. ```ts const nestedNode = fixedSizeTypeNode(stringTypeNode('utf8'), 10); isNestedTypeNode(nestedNode, 'stringTypeNode'); // true isNestedTypeNode(nestedNode, 'numberTypeNode'); // false isNestedTypeNode(nestedNode, ['stringTypeNode', 'numberTypeNode']); // true ``` ### `assertIsNestedTypeNode(node, kind)` This function asserts that the final `TypeNode` of a nested type node is of the given kind or kinds. It throws an error if the assertion fails. ```ts const nestedNode = fixedSizeTypeNode(stringTypeNode('utf8'), 10); assertIsNestedTypeNode(nestedNode, 'stringTypeNode'); // Ok assertIsNestedTypeNode(nestedNode, 'numberTypeNode'); // Throws an error assertIsNestedTypeNode(nestedNode, ['stringTypeNode', 'numberTypeNode']); // Ok ``` ================================================ FILE: packages/nodes/docs/typeNodes/NumberTypeNode.md ================================================ # `NumberTypeNode` A type node representing a number with a specific format and endianess. ## Attributes ### Data | Attribute | Type | Description | | --------- | --------------------------------- | -------------------------------------------------------------------------------- | | `kind` | `"numberTypeNode"` | The node discriminator. | | `format` | [`NumberFormat`](#number-formats) | The format of the number (see below for more details). | | `endian` | `"le" \| "be"` | The endianess of the number. `"le"` for little-endian and `"be"` for big-endian. | ### Children _This node has no children._ ## Number Formats A number can be encoded in many different ways. The following formats are supported. ### Integers If your number is an integer, you may choose to encode it as a signed or unsigned integer using different byte lengths. We currently support encoding integers in 1, 2, 4, 8, and 16 bytes. | Length | Signed integer | Unsigned integer | | ------- | -------------- | ---------------- | | 8-bit | `'i8'` | `'u8'` | | 16-bit | `'i16'` | `'u16'` | | 32-bit | `'i32'` | `'u32'` | | 64-bit | `'i64'` | `'u64'` | | 128-bit | `'i128'` | `'u128'` | ### Floating Point Numbers If your number is a floating point number, you may choose to encode it as a 32-bit or 64-bit floating point number. | Precision | Decimal number | | --------- | -------------- | | 32-bit | `'f32'` | | 64-bit | `'f64'` | ### Variable Length Integers We also support encoding integers using variable byte lengths. Currently, we support the `shortU16` encoding which works as follows: | Format | Description | | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `shortU16` | Stores an unsigned integer using between 1 to 3 bytes depending on the value of that integer. If the provided integer is equal to or lower than `0x7f`, it will be stored as-is, using a single byte. However, if the integer is above `0x7f`, then the top bit is set and the remaining value is stored in the next bytes. Each byte follows the same pattern until the third byte. The third byte, if needed, uses all 8 bits to store the last byte of the original value. | ## Functions ### `numberTypeNode(format, endian)` Helper function that creates a `NumberTypeNode` object from a provided format and endianess. ```ts const littleEndianNode = numberTypeNode('u32'); // Little-endian by default. const bigEndianNode = numberTypeNode('u32', 'be'); ``` ### `isSignedInteger(node)` Checks if the provided `NumberTypeNode` represents a signed integer. ```ts isSignedInteger(numberTypeNode('u32')); // false isSignedInteger(numberTypeNode('i32')); // true ``` ### `isUnsignedInteger(node)` Checks if the provided `NumberTypeNode` represents an unsigned integer. ```ts isUnsignedInteger(numberTypeNode('u32')); // true isUnsignedInteger(numberTypeNode('i32')); // false ``` ### `isInteger(node)` Checks if the provided `NumberTypeNode` represents an integer. ```ts isInteger(numberTypeNode('u32')); // true isInteger(numberTypeNode('i32')); // true isInteger(numberTypeNode('f32')); // false ``` ### `isDecimal(node)` Checks if the provided `NumberTypeNode` represents a decimal number. ```ts isDecimal(numberTypeNode('u32')); // false isDecimal(numberTypeNode('i32')); // false isDecimal(numberTypeNode('f32')); // true ``` ## Examples ### Encoding `u32` integers ![Diagram](https://github.com/codama-idl/codama/assets/3642397/4bb1ae23-c69f-4c9f-a7ec-8f971d061667) ```ts numberTypeNode('u32'); // 5 => 0x00000000 // 42 => 0x2A000000 // 65535 => 0xFFFF0000 ``` ### Encoding `f32` big-endian decimal numbers ![Diagram](https://github.com/codama-idl/codama/assets/3642397/d9cbfd3c-b8a2-4c13-a8a8-a11e7ed5d422) ```ts numberTypeNode('f32', 'be'); // 1 => 0x3F800000 // -42 => 0xC2280000 // 3.1415 => 0x40490E56 ``` ### Encoding `shortU16` integers ![Diagram](https://github.com/codama-idl/codama/assets/3642397/73e12166-cdaa-4fca-ae2a-67937f8b130e) ```ts numberTypeNode('shortU16'); // 42 => 0x2A // 128 => 0x8001 // 16384 => 0x808001 ``` ================================================ FILE: packages/nodes/docs/typeNodes/OptionTypeNode.md ================================================ # `OptionTypeNode` A node that represents an optional item using a child `TypeNode`. The item can either be present — i.e. `Some` — or absent — i.e. `None` — depending on the value of a prefixed `NumberTypeNode`. If the prefixed value is `1`, the item is present and the child node should be encoded/decoded accordingly. However, if the prefixed value is `0`, the item is absent and no further encoding/decoding should be performed. However, if the `fixed` option is set to `true`, the encoded `None` value will be padded with zeroes matching the length of the fixed-size item to ensure the option type is fixed-size regardless of the presence of the item. ## Attributes ### Data | Attribute | Type | Description | | --------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `kind` | `"optionTypeNode"` | The node discriminator. | | `fixed` | `boolean` | (Optional) Whether or not we should pad the `None` value with zeroes matching the fixed length of the item. This option must only be set to `true` if the `item` node is of fixed-size. Defaults to `false`. | ### Children | Attribute | Type | Description | | --------- | -------------------------------------------------------------------------------- | ------------------------------------------- | | `item` | [`TypeNode`](./README.md) | The item that may exist. | | `prefix` | [`NestedTypeNode`](./NestedTypeNode.md)<[`NumberTypeNode`](./NumberTypeNode.md)> | The number type node to use for the prefix. | ## Functions ### `optionTypeNode(item, options?)` Helper function that creates a `OptionTypeNode` object from the item `TypeNode` and an optional configuration object. ```ts const node = optionTypeNode(publicKeyTypeNode()); const nodeWithCustomPrefix = optionTypeNode(publicKeyTypeNode(), { prefix: numberTypeNode('u16') }); const fixedNode = optionTypeNode(publicKeyTypeNode(), { fixed: true }); ``` ## Examples ### An optional UTF-8 with a u16 prefix ```ts optionTypeNode(stringTypeNode('UTF-8'), { prefix: numberTypeNode('u16') }); // None => 0x0000 // Some("Hello") => 0x010048656C6C6F ``` ### A fixed optional u32 number ```ts optionTypeNode(numberTypeNode('u32'), { fixed: true }); // None => 0x0000000000 // Some(42) => 0x012A000000 ``` ================================================ FILE: packages/nodes/docs/typeNodes/PostOffsetTypeNode.md ================================================ # `PostOffsetTypeNode` A node that wraps another type node and offsets the encoding/decoding cursor by a provided amount using a [provided strategy](#offset-strategies). Since this is the `PostOffsetTypeNode`, the offset is applied _after_ the child node has been encoded/decoded. Therefore, this node is useful to move the cursor around after the child node has been processed. See the [`PreOffsetTypeNode`](./PreOffsetTypeNode.md) for the opposite behavior. This node can be used to create [`NestedTypeNodes`](./NestedTypeNode.md). ## Attributes ### Data | Attribute | Type | Description | | ---------- | ----------------------------------------------------- | ------------------------------------------------- | | `kind` | `"postOffsetTypeNode"` | The node discriminator. | | `offset` | `number` | The offset amount in bytes. | | `strategy` | `"absolute" \| "padded" \| "preOffset" \| "relative"` | The offset strategy (see below for more details). | ### Children | Attribute | Type | Description | | --------- | ------------------------- | ------------------------- | | `type` | [`TypeNode`](./README.md) | The child node to offset. | ## Offset strategies In order to illustrate the behavior of each strategy, we will use the following buffer as an example. The `99` bytes represent the child node's encoded value and the `FF` bytes represent the next bytes to be encoded (after the child node) in order to illustrate the _post_ cursor position. ``` 0x00000099FF000000; | └-- Initial post-offset └-- Pre-offset ``` The following offset strategies are available. ### `relative` The cursor is moved to the right by the provided offset. ``` offset = 2 0x000000990000FF00; └-- Post-offset ``` When a negative offset is provided, the cursor is moved the left instead. ``` offset = -2 0x0000FF9900000000; └-- Post-offset ``` ### `absolute` The cursor is moved to an absolute position in the buffer. ``` offset = 0 0xFF00009900000000; └-- Post-offset ``` When a negative offset is provided, the cursor is moved backwards from the end of the buffer. ``` offset = -2 0x000000990000FF00; └-- Post-offset ``` > [!IMPORTANT] > Please note that some `TypeNodes` affect the buffer that is available to us which means, depending on where we are in the `TypeNode` tree, we may not have access to the entire buffer. > > For instance, say you are inside a `FixedSizeTypeNode`. Once the content of the `FixedSizeTypeNode` has been encoded/decoded, the buffer will be truncated or padded to match the provided fixed size. This means, when inside that node, we are essentially "boxed" in a sub-buffer. This sub-buffer is the one that will be affected by the `absolute` offset. > > Here is an exhaustive list of all `TypeNodes` that create sub-buffers: > > - [`FixedSizeTypeNode`](./FixedSizeTypeNode.md) > - [`SentinelTypeNode`](./SentinelTypeNode.md) > - [`SizePrefixTypeNode`](./SizePrefixTypeNode.md) ### `padded` The cursor is moved to the right by the provided offset **and the buffer size is increased** by the offset amount. This allows us to add padding bytes to the buffer. ``` offset = 2 0x000000990000FF000000; <- Size = 10 (initially 8) └-- Post-offset ``` Reciprocally, when a negative offset is provided, the cursor is moved the left and the buffer size is decreased. ``` offset = -2 0x0000FF990000; <- Size = 6 (initially 8) └-- Post-offset ``` ### `preOffset` The cursor is moved **to the right of the pre-offset** by the provided offset. ``` offset = 2 0x0000009900FF0000; | └-- Post-offset = Pre-offset + 2 └-- Pre-offset ``` When a negative offset is provided, the cursor is moved the left of the pre-offset instead. ``` offset = -2 0x00FF009900000000; | └-- Pre-offset └-- Post-offset = Pre-offset - 2 ``` ## Functions ### `postOffsetTypeNode(type, offset, strategy?)` Helper function that creates a `PostOffsetTypeNode` object from a child `TypeNode`, an offset and — optionally — a strategy which defaults to `"relative"`. ```ts const relativeOffsetNode = postOffsetTypeNode(numberTypeNode('u32'), 2); const absoluteOffsetNode = postOffsetTypeNode(numberTypeNode('u32'), -2, 'absolute'); ``` ## Examples ### A right-padded u32 number ```ts postOffsetTypeNode(numberTypeNode('u32'), 4, 'padded'); // 42 => 0x2A00000000000000 ``` ### A u32 number overwritten by a u16 number ```ts tupleTypleNode([postOffsetTypeNode(numberTypeNode('u32'), -2), numberTypeNode('u16')]); // [1, 2] => 0x01000200 // [0xFFFFFFFF, 42] => 0xFFFF2A00 ``` ================================================ FILE: packages/nodes/docs/typeNodes/PreOffsetTypeNode.md ================================================ # `PreOffsetTypeNode` A node that wraps another type node and offsets the encoding/decoding cursor by a provided amount using a [provided strategy](#offset-strategies). Since this is the `PreOffsetTypeNode`, the offset is applied _before_ the child node has been encoded/decoded. Therefore, this node is useful to move encoded value of the child node itself. See the [`PostOffsetTypeNode`](./PostOffsetTypeNode.md) for the opposite behavior. This node can be used to create [`NestedTypeNodes`](./NestedTypeNode.md). ## Attributes ### Data | Attribute | Type | Description | | ---------- | -------------------------------------- | ------------------------------------------------- | | `kind` | `"preOffsetTypeNode"` | The node discriminator. | | `offset` | `number` | The offset amount in bytes. | | `strategy` | `"absolute" \| "padded" \| "relative"` | The offset strategy (see below for more details). | ### Children | Attribute | Type | Description | | --------- | ------------------------- | ------------------------- | | `type` | [`TypeNode`](./README.md) | The child node to offset. | ## Offset strategies In order to illustrate the behavior of each strategy, we will use the following buffer as an example. The `99` bytes represent some previously encoded value for reference and the `FF` bytes represent the child node's encoded value which we will be moving by changing its pre-offset. ``` 0x00000099FF000000; └-- Initial pre-offset ``` The following offset strategies are available. ### `relative` The cursor is moved to the right by the provided offset. ``` offset = 2 0x000000990000FF00; └-- Pre-offset ``` When a negative offset is provided, the cursor is moved the left instead. ``` offset = -2 0x0000FF9900000000; └-- Pre-offset ``` ### `absolute` The cursor is moved to an absolute position in the buffer. ``` offset = 0 0xFF00009900000000; └-- Pre-offset ``` When a negative offset is provided, the cursor is moved backwards from the end of the buffer. ``` offset = -2 0x000000990000FF00; └-- Pre-offset ``` > [!IMPORTANT] > Please note that some `TypeNodes` affect the buffer that is available to us which means, depending on where we are in the `TypeNode` tree, we may not have access to the entire buffer. > > For instance, say you are inside a `FixedSizeTypeNode`. Once the content of the `FixedSizeTypeNode` has been encoded/decoded, the buffer will be truncated or padded to match the provided fixed size. This means, when inside that node, we are essentially "boxed" in a sub-buffer. This sub-buffer is the one that will be affected by the `absolute` offset. > > Here is an exhaustive list of all `TypeNodes` that create sub-buffers: > > - [`FixedSizeTypeNode`](./FixedSizeTypeNode.md) > - [`SentinelTypeNode`](./SentinelTypeNode.md) > - [`SizePrefixTypeNode`](./SizePrefixTypeNode.md) ### `padded` The cursor is moved to the right by the provided offset **and the buffer size is increased** by the offset amount. This allows us to add padding bytes to the buffer. ``` offset = 2 0x000000990000FF000000; <- Size = 10 (initially 8) └-- Pre-offset ``` Reciprocally, when a negative offset is provided, the cursor is moved the left and the buffer size is decreased. ``` offset = -2 0x0000FF990000; <- Size = 6 (initially 8) └-- Pre-offset ``` ## Functions ### `preOffsetTypeNode(type, offset, strategy?)` Helper function that creates a `PreOffsetTypeNode` object from a child `TypeNode`, an offset and — optionally — a strategy which defaults to `"relative"`. ```ts const relativeOffsetNode = preOffsetTypeNode(numberTypeNode('u32'), 2); const absoluteOffsetNode = preOffsetTypeNode(numberTypeNode('u32'), -2, 'absolute'); ``` ## Examples ### A left-padded u32 number ```ts preOffsetTypeNode(numberTypeNode('u32'), 4, 'padded'); // 42 => 0x000000002A000000 ``` ### A u32 number overwritten by a u16 number ```ts tupleTypleNode([numberTypeNode('u32'), preOffsetTypeNode(numberTypeNode('u16'), -2)]); // [1, 2] => 0x01000200 // [0xFFFFFFFF, 42] => 0xFFFF2A00 ``` ================================================ FILE: packages/nodes/docs/typeNodes/PublicKeyTypeNode.md ================================================ # `PublicKeyTypeNode` A node that represents a 32-byte public key. ## Attributes ### Data | Attribute | Type | Description | | --------- | --------------------- | ----------------------- | | `kind` | `"publicKeyTypeNode"` | The node discriminator. | ### Children _This node has no children._ ## Functions ### `publicKeyTypeNode()` Helper function that creates a `PublicKeyTypeNode` object. ```ts const node = publicKeyTypeNode(); ``` ================================================ FILE: packages/nodes/docs/typeNodes/README.md ================================================ # `TypeNode` (abstract) The `TypeNode` type helper represents all the available type nodes as well as the `DefinedTypeLinkNode` which allows us to reuse a pre-defined type node. Note that `TypeNode` is a type alias and cannot be used directly as a node. Instead you may use one of the following nodes: - [`AmountTypeNode`](./AmountTypeNode.md) - [`ArrayTypeNode`](./ArrayTypeNode.md) - [`BooleanTypeNode`](./BooleanTypeNode.md) - [`BytesTypeNode`](./BytesTypeNode.md) - [`DateTimeTypeNode`](./DateTimeTypeNode.md) - [`DefinedTypeLinkNode`](../linkNodes/DefinedTypeLinkNode.md) - [`EnumTypeNode`](./EnumTypeNode.md) - [`FixedSizeTypeNode`](./FixedSizeTypeNode.md) - [`HiddenPrefixTypeNode`](./HiddenPrefixTypeNode.md) - [`HiddenSuffixTypeNode`](./HiddenSuffixTypeNode.md) - [`MapTypeNode`](./MapTypeNode.md) - [`NumberTypeNode`](./NumberTypeNode.md) - [`OptionTypeNode`](./OptionTypeNode.md) - [`PostOffsetTypeNode`](./PostOffsetTypeNode.md) - [`PreOffsetTypeNode`](./PreOffsetTypeNode.md) - [`PublicKeyTypeNode`](./PublicKeyTypeNode.md) - [`RemainderOptionTypeNode`](./RemainderOptionTypeNode.md) - [`SentinelTypeNode`](./SentinelTypeNode.md) - [`SetTypeNode`](./SetTypeNode.md) - [`SizePrefixTypeNode`](./SizePrefixTypeNode.md) - [`SolAmountTypeNode`](./SolAmountTypeNode.md) - [`StringTypeNode`](./StringTypeNode.md) - [`StructTypeNode`](./StructTypeNode.md) - [`TupleTypeNode`](./TupleTypeNode.md) - [`ZeroableOptionTypeNode`](./ZeroableOptionTypeNode.md) ================================================ FILE: packages/nodes/docs/typeNodes/RemainderOptionTypeNode.md ================================================ # `RemainderOptionTypeNode` A node that represents an optional item using a child `TypeNode`. The item can either be present — i.e. `Some` — or absent — i.e. `None` — depending on whether or not there are remaining bytes in the buffer. If there are remaining bytes, the item is present and the child node should be encoded/decoded accordingly. However, if there are no remaining bytes, the item is absent and no further encoding/decoding should be performed. ## Attributes ### Data | Attribute | Type | Description | | --------- | --------------------------- | ----------------------- | | `kind` | `"remainderOptionTypeNode"` | The node discriminator. | ### Children | Attribute | Type | Description | | --------- | ------------------------- | ------------------------ | | `item` | [`TypeNode`](./README.md) | The item that may exist. | ## Functions ### `remainderOptionTypeNode(item)` Helper function that creates a `RemainderOptionTypeNode` object from the item `TypeNode`. ```ts const node = remainderOptionTypeNode(publicKeyTypeNode()); ``` ## Examples ### An optional UTF-8 string using remaining bytes ```ts remainderOptionTypeNode(stringTypeNode('UTF-8')); // None => 0x // Some("Hello") => 0x48656C6C6F ``` ================================================ FILE: packages/nodes/docs/typeNodes/SentinelTypeNode.md ================================================ # `SentinelTypeNode` A node that limits the size of a child node using a sentinel value. The sentinel value is a constant value that is used to determine the end of the child node. When encoding, the sentinel value is written after the child node. When decoding, the child node is decoded until the sentinel value is encountered, at which point the decoding stops and the sentinel value is discarded. Note that, for the `SentinelTypeNode` to work, the sentinel value must not be included in the child node's encoding. This node can be used to create [`NestedTypeNodes`](./NestedTypeNode.md). ## Attributes ### Data | Attribute | Type | Description | | --------- | -------------------- | ----------------------- | | `kind` | `"sentinelTypeNode"` | The node discriminator. | ### Children | Attribute | Type | Description | | ---------- | -------------------------------------------------------- | ----------------------------------------------------- | | `type` | [`TypeNode`](./README.md) | The child node to limit. | | `sentinel` | [`ConstantValueNode`](./valueNodes/ConstantValueNode.md) | The sentinel value marking the end of the child node. | ## Functions ### `sentinelTypeNode(type, sentinel)` Helper function that creates a `SentinelTypeNode` object from a type node and a constant value node. ```ts const sentinel = constantValueNode(bytesTypeNode(), bytesValueNode('base16', 'ff')); const node = sentinelTypeNode(stringTypeNode('utf8'), sentinel); ``` ## Examples ### A UTF-8 string terminated by 0xFF ```ts sentinelTypeNode(stringTypeNode('utf8'), constantValueNode(bytesTypeNode(), bytesValueNode('base16', 'ff'))); // Hello => 0x48656C6C6FFF ``` ================================================ FILE: packages/nodes/docs/typeNodes/SetTypeNode.md ================================================ # `SetTypeNode` A node that represents a set of unique items. The type of each item is defined by the `item` child node and the length of the set is determined by the `count` child node. ## Attributes ### Data | Attribute | Type | Description | | --------- | --------------- | ----------------------- | | `kind` | `"setTypeNode"` | The node discriminator. | ### Children | Attribute | Type | Description | | --------- | -------------------------------------- | ---------------------------------------------- | | `item` | [`TypeNode`](./README.md) | The type of each item in the set. | | `count` | [`CountNode`](../countNodes/README.md) | The strategy to determine the size of the set. | ## Functions ### `setTypeNode(item, count)` Helper function that creates a `SetTypeNode` object from a `TypeNode` and a `CountNode`. ```ts const node = setTypeNode(publicKeyTypeNode(), prefixedCountNode(numberTypeNode('u32'))); ``` ## Examples ### u32 prefixed array of u8 numbers ```ts setTypeNode(numberTypeNode('u8'), prefixedCountNode(numberTypeNode('u32'))); // Set (1, 2, 3) => 0x03000000010203 ``` ================================================ FILE: packages/nodes/docs/typeNodes/SizePrefixTypeNode.md ================================================ # `SizePrefixTypeNode` A node that limits the size of a child node using a size prefix that stores the size of the child node in bytes. When encoding, the size of the child node is written before the child node itself. When decoding, the size is read first and used to determine the length of the child node. This node can be used to create [`NestedTypeNodes`](./NestedTypeNode.md). ## Attributes ### Data | Attribute | Type | Description | | --------- | ---------------------- | ----------------------- | | `kind` | `"sizePrefixTypeNode"` | The node discriminator. | ### Children | Attribute | Type | Description | | --------- | -------------------------------------------------------------------------------- | ------------------------------------------------------ | | `type` | [`TypeNode`](./README.md) | The child node to size. | | `prefix` | [`NestedTypeNode`](./NestedTypeNode.md)<[`NumberTypeNode`](./NumberTypeNode.md)> | The node used to determine the size of the child node. | ## Functions ### `sizePrefixTypeNode(type, prefix)` Helper function that creates a `SizePrefixTypeNode` object from a type node and a `NumberTypeNode` prefix. ```ts const node = sizePrefixTypeNode(stringTypeNode('utf8'), numberTypeNode('u32')); ``` ## Examples ### A UTF-8 string prefixed with a u16 size ```ts sizePrefixTypeNode(stringTypeNode('utf8'), numberTypeNode('u16')); // "" => 0x0000 // "Hello" => 0x050048656C6C6F ``` ================================================ FILE: packages/nodes/docs/typeNodes/SolAmountTypeNode.md ================================================ # `SolAmountTypeNode` A node that wraps a [`NumberTypeNode`](./NumberTypeNode.md) to mark it as representing a Solana amount in lamports. Note that this node is equivalent to using a [`AmountTypeNode`](./AmountTypeNode.md) with 9 decimals and `SOL` as the unit. ## Attributes ### Data | Attribute | Type | Description | | --------- | --------------------- | ----------------------- | | `kind` | `"solAmountTypeNode"` | The node discriminator. | ### Children | Attribute | Type | Description | | --------- | -------------------------------------------------------------------------------- | ------------------------ | | `number` | [`NestedTypeNode`](./NestedTypeNode.md)<[`NumberTypeNode`](./NumberTypeNode.md)> | The number node to wrap. | ## Functions ### `solAmountTypeNode(number)` Helper function that creates a `SolAmountTypeNode` object from a `NumberTypeNode`. ```ts const node = solAmountTypeNode(numberTypeNode('u64')); ``` ## Examples ### u64 Solana amounts ```ts solAmountTypeNode(numberTypeNode('u64')); // 1.5 SOL => 0x002F685900000000 // 300 SOL => 0x00B864D945000000 ``` ================================================ FILE: packages/nodes/docs/typeNodes/StringTypeNode.md ================================================ # `StringTypeNode` A node that represents an unbounded string from a given encoding. It can be shaped in size using nodes such as the [`SizePrefixTypeNode`](./SizePrefixTypeNode.md) or the [`FixedSizeTypeNode`](./FixedSizeTypeNode.md). ## Attributes ### Data | Attribute | Type | Description | | ---------- | -------------------------------------------- | --------------------------- | | `kind` | `"stringTypeNode"` | The node discriminator. | | `encoding` | `"base16" \| "base58" \| "base64" \| "utf8"` | The encoding of the string. | ### Children _This node has no children._ ## Functions ### `stringTypeNode(encoding)` Helper function that creates a `StringTypeNode` object from an encoding. ```ts const node = stringTypeNode('utf8'); ``` ================================================ FILE: packages/nodes/docs/typeNodes/StructFieldTypeNode.md ================================================ # `StructFieldTypeNode` A node that describes a field in a object or struct. It contains a name, a type, and optionally a default value. ## Attributes ### Data | Attribute | Type | Description | | ---------------------- | ------------------------- | ---------------------------------------------------------------------- | | `kind` | `"structFieldTypeNode"` | The node discriminator. | | `name` | `CamelCaseString` | The name of the field. | | `docs` | `string[]` | Markdown documentation for the type. | | `defaultValueStrategy` | `"omitted" \| "optional"` | (Optional) The strategy to use for the default value node if provided. | ### Children | Attribute | Type | Description | | -------------- | -------------------------------------- | ------------------------------------------ | | `type` | [`TypeNode`](./README.md) | The data type of the field. | | `defaultValue` | [`ValueNode`](../valueNodes/README.md) | (Optional) The default value of the field. | ## Functions ### `structFieldTypeNode(input)` Helper function that creates a `StructFieldTypeNode` object from an input object. ```ts const authorityField = structFieldTypeNode({ name: 'authority', type: publicKeyTypeNode(), }); const ageFieldWithDefaultValue = structFieldTypeNode({ name: 'age', type: numberTypeNode('u8'), defaultValue: numberValueNode(42), }); ``` ## Examples ### A struct field with a default value ```ts structFieldTypeNode({ name: 'age', type: numberTypeNode('u8'), defaultValue: numberValueNode(42), }); // {} => 0x2A // { age: 29 } => 0x1D ``` ================================================ FILE: packages/nodes/docs/typeNodes/StructTypeNode.md ================================================ # `StructTypeNode` A node representing an object or struct with named fields. Each field is represented by a dedicated [`StructFieldTypeNode`](./StructFieldTypeNode.md). Each field is encoded and decoded in the order they are defined. ## Attributes ### Data | Attribute | Type | Description | | --------- | ------------------ | ----------------------- | | `kind` | `"structTypeNode"` | The node discriminator. | ### Children | Attribute | Type | Description | | --------- | --------------------------------------------------- | ------------------------- | | `fields` | [`StructFieldTypeNode`](./StructFieldTypeNode.md)[] | The fields of the struct. | ## Functions ### `structTypeNode(fields)` Helper function that creates a `StructTypeNode` object from an array of `StructFieldTypeNode` objects. ```ts const node = structTypeNode([ structFieldTypeNode({ name: 'authority', type: publicKeyTypeNode() }), structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64') }), ]); ``` ## Examples ### A struct storing a person's name and age ```ts structTypeNode([ structFieldTypeNode({ name: 'name', type: fixedSizeTypeNode(stringTypeNode('utf8'), 10) }), structFieldTypeNode({ name: 'age', type: numberTypeNode('u8') }), ]); // { name: Alice, age: 42 } => 0x416C69636500000000002A ``` ================================================ FILE: packages/nodes/docs/typeNodes/TupleTypeNode.md ================================================ # `TupleTypeNode` A node that represents a tuple of types such that each element in the tuple is represented by a dedicated [`TypeNode`](./TypeNode.md). Each item is encoded and decoded in the order they are defined. ## Attributes ### Data | Attribute | Type | Description | | --------- | ----------------- | ----------------------- | | `kind` | `"tupleTypeNode"` | The node discriminator. | ### Children | Attribute | Type | Description | | --------- | --------------------------- | ----------------------------------- | | `items` | [`TypeNode`](./README.md)[] | The type of each item in the tuple. | ## Functions ### `tupleTypeNode(items)` Helper function that creates a `TupleTypeNode` object from an array of `TypeNodes`. ```ts const node = tupleTypeNode([publicKeyTypeNode(), numberTypeNode('u64')]); ``` ## Examples ### A tuple storing a person's name and age ```ts tupleTypeNode([fixedSizeTypeNode(stringTypeNode('utf8'), 10), numberTypeNode('u8')]); // (Alice, 42) => 0x416C69636500000000002A ``` ================================================ FILE: packages/nodes/docs/typeNodes/ZeroableOptionTypeNode.md ================================================ # `ZeroableOptionTypeNode` A node that represents an optional item using a child `TypeNode` of fixed-size. Contrary to the [`OptionTypeNode`](./OptionTypeNode.md), this node does not use a number prefix to determine if the item is present or not. Instead, it checks whether the fixed-size item is filled with zeroes. If it is, then we consider the item to be absent — i.e. `None` — otherwise, it is present — i.e. `Some` — and the child node should be encoded/decoded accordingly. An optional `zeroValue` constant node can also be provided to determine the customise the zero value of the fixed-size item. For instance if the `zeroValue` is `0xFFFFFFFF`, then a buffer with this value will be considered as `None` and anyting else will be considered as `Some`. ## Attributes ### Data | Attribute | Type | Description | | --------- | -------------------------- | ----------------------- | | `kind` | `"zeroableOptionTypeNode"` | The node discriminator. | ### Children | Attribute | Type | Description | | ----------- | -------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | | `item` | [`TypeNode`](./README.md) | The item that may exist. Must be of fixed-size. | | `zeroValue` | [`ConstantValueNode`](./valueNodes/ConstantValueNode.md) | (Optional) The constant value representing `None`. Defaults to filling the size of the item with zeroes. | ## Functions ### `zeroableOptionTypeNode(item, zeroValue?)` Helper function that creates a `ZeroableOptionTypeNode` object from a `TypeNode` and an optional zero value. ```ts const node = zeroableOptionTypeNode(publicKeyTypeNode()); const nodeWithZeroValue = zeroableOptionTypeNode( numbetypeNode('u32'), constantValueNode(bytesTypeNode(), bytesValueNode('base16', 'ffffffff')), ); ``` ## Examples ### a u32 zeroable option ```ts zeroableOptionTypeNode(numbetypeNode('u32')); // None => 0x00000000 // Some(42) => 0x2A000000 ``` ### a u32 zeroable option with a custom zero value ```ts zeroableOptionTypeNode(numbetypeNode('u32'), constantValueNode(bytesTypeNode(), bytesValueNode('base16', 'ffffffff'))); // None => 0xFFFFFFFF // Some(42) => 0x2A000000 ``` ================================================ FILE: packages/nodes/docs/valueNodes/ArrayValueNode.md ================================================ # `ArrayValueNode` A node that represents an array of values — e.g. `[1, 2, 3]`. ## Attributes ### Data | Attribute | Type | Description | | --------- | ------------------ | ----------------------- | | `kind` | `"arrayValueNode"` | The node discriminator. | ### Children | Attribute | Type | Description | | --------- | ---------------------------- | -------------------------------- | | `items` | [`ValueNode`](./README.md)[] | The value of all items in array. | ## Functions ### `arrayValueNode(items)` Helper function that creates a `ArrayValueNode` object from an array of value nodes. ```ts const node = arrayValueNode([numberValueNode(1), numberValueNode(2), numberValueNode(3)]); ``` ================================================ FILE: packages/nodes/docs/valueNodes/BooleanValueNode.md ================================================ # `BooleanValueNode` A node that represents a boolean value — e.g. `true`. ## Attributes ### Data | Attribute | Type | Description | | --------- | -------------------- | ----------------------- | | `kind` | `"booleanValueNode"` | The node discriminator. | | `boolean` | `boolean` | The boolean value. | ### Children _This node has no children._ ## Functions ### `booleanValueNode(items)` Helper function that creates a `BooleanValueNode` object from a boolean. ```ts const node = booleanValueNode(true); ``` ================================================ FILE: packages/nodes/docs/valueNodes/BytesValueNode.md ================================================ # `BytesValueNode` A node that represents a value in bytes — e.g. `0x010203`. ## Attributes ### Data | Attribute | Type | Description | | ---------- | -------------------------------------------- | ------------------------------------- | | `kind` | `"bytesValueNode"` | The node discriminator. | | `encoding` | `"base16" \| "base58" \| "base64" \| "utf8"` | The encoding of the `data` attribute. | | `data` | `string` | The encoded data. | ### Children _This node has no children._ ## Functions ### `bytesValueNode(encoding, data)` Helper function that creates a `BytesValueNode` object from an encoding and an encoded data string. ```ts const node = bytesValueNode('base16', '010203'); const utf8Node = bytesValueNode('utf8', 'Hello'); ``` ================================================ FILE: packages/nodes/docs/valueNodes/ConstantValueNode.md ================================================ # `ConstantValueNode` A node that represents a constant value from a [`TypeNode`](../typeNodes/README.md) and a [`ValueNode`](./README.md). ## Attributes ### Data | Attribute | Type | Description | | --------- | --------------------- | ----------------------- | | `kind` | `"constantValueNode"` | The node discriminator. | ### Children | Attribute | Type | Description | | --------- | ------------------------------------ | -------------------------- | | `type` | [`TypeNode`](../typeNodes/README.md) | The type of the constant. | | `value` | [`ValueNode`](./README.md) | The value of the constant. | ## Functions ### `constantValueNode(type, value)` Helper function that creates a `ConstantValueNode` object from a type and a value node ```ts const node = constantValueNode(numberTypeNode('u32'), numberValueNode(42)); ``` ### `constantValueNodeFromString(encoding, data)` Helper function that creates a `ConstantValueNode` object of type `StringTypeNode` from an encoding and a string of data. ```ts constantValueNodeFromString('utf8', 'Hello'); // Equivalent to: constantValueNode(stringTypeNode('utf8'), stringValueNode('Hello')); ``` ### `constantValueNodeFromBytes(encoding, data)` Helper function that creates a `ConstantValueNode` object of type `BytesTypeNode` from an encoding and a string of data. ```ts constantValueNodeFromBytes('base16', 'FF99CC'); // Equivalent to: constantValueNode(bytesTypeNode(), bytesValueNode('base16', 'FF99CC')); ``` ================================================ FILE: packages/nodes/docs/valueNodes/EnumValueNode.md ================================================ # `EnumValueNode` A node representing a value of an enum type. That is, it selects a specific variant and optionally provides the data associated with that variant. ## Attributes ### Data | Attribute | Type | Description | | --------- | ----------------- | ---------------------------------- | | `kind` | `"enumValueNode"` | The node discriminator. | | `variant` | `CamelCaseString` | The name of the variant to select. | ### Children | Attribute | Type | Description | | --------- | ------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------- | | `enum` | [`DefinedTypeLinkNode`](./typeNodes/DefinedTypeLinkNode.md) | The linked enum type definition. The `DefinedTypeNode` it links to must contain an `EnumTypeNode`. | | `value` | [`StructValueNode`](./StructValueNode.md) \| [`TupleValueNode`](./TupleValueNode.md) | (Optional) The data of the enum variant if required. | ## Functions ### `enumValueNode(enum, variant, value?)` Helper function that creates a `EnumValueNode` object from an enum type, a variant name, and an optional value node for its data. The first argument can be a `DefinedTypeLinkNode` or a `string` matching the name of the defined enum type. ```ts const node = enumValueNode('myEnum', 'myVariant'); const nodeWithExplicitEnum = enumValueNode(definedTypeLinkNode('myEnum'), 'myVariant'); const nodeWithData = enumValueNode( 'myEnum', 'myVariantWithData', structValueNode([ structFieldValueNode('name', stringValueNode('Alice')), structFieldValueNode('age', numberValueNode(42)), ]), ); ``` ================================================ FILE: packages/nodes/docs/valueNodes/MapEntryValueNode.md ================================================ # `MapEntryValueNode` A node that represents the concrete value of a map entry. For example, the map `{ total: 42 }` has only one entry such that its key is a `"total"` string and its value is a `42` number. ## Attributes ### Data | Attribute | Type | Description | | --------- | --------------------- | ----------------------- | | `kind` | `"mapEntryValueNode"` | The node discriminator. | ### Children | Attribute | Type | Description | | --------- | -------------------------- | ----------------------- | | `key` | [`ValueNode`](./README.md) | The key of the entry. | | `value` | [`ValueNode`](./README.md) | The value of the entry. | ## Functions ### `mapEntryValueNode(key, value)` Helper function that creates a `MapEntryValueNode` object from two `ValueNode` objects. The first one represents the key of the entry, and the second one represents the value of the entry. ```ts const node = mapEntryValueNode(stringValueNode('total'), numberValueNode(42)); ``` ================================================ FILE: packages/nodes/docs/valueNodes/MapValueNode.md ================================================ # `MapValueNode` A node that represents the value of a map. ## Attributes ### Data | Attribute | Type | Description | | --------- | ---------------- | ----------------------- | | `kind` | `"mapValueNode"` | The node discriminator. | ### Children | Attribute | Type | Description | | --------- | ----------------------------------------------- | ------------------------------------ | | `entries` | [`MapEntryValueNode`](./MapEntryValueNode.md)[] | The value of all entries in the map. | ## Functions ### `mapValueNode(entries)` Helper function that creates a `MapValueNode` object from an array of `MapEntryValueNode` objects. Each object represents a key-value pair in the map. ```ts const node = mapValueNode([ mapEntryValueNode(stringValueNode('apples'), numberValueNode(12)), mapEntryValueNode(stringValueNode('bananas'), numberValueNode(34)), mapEntryValueNode(stringValueNode('carrots'), numberValueNode(56)), ]); ``` ================================================ FILE: packages/nodes/docs/valueNodes/NoneValueNode.md ================================================ # `NoneValueNode` A node that represents the absence of a value. For instance, this could be set as a default value for a field of type [`OptionTypeNode`](../typeNodes/OptionTypeNode.md). ## Attributes ### Data | Attribute | Type | Description | | --------- | ----------------- | ----------------------- | | `kind` | `"noneValueNode"` | The node discriminator. | ### Children _This node has no children._ ## Functions ### `noneValueNode()` Helper function that creates a `NoneValueNode` object. ```ts const node = noneValueNode(); ``` ================================================ FILE: packages/nodes/docs/valueNodes/NumberValueNode.md ================================================ # `NumberValueNode` A node that represents a number value — e.g. `42`. ## Attributes ### Data | Attribute | Type | Description | | --------- | ------------------- | ----------------------- | | `kind` | `"numberValueNode"` | The node discriminator. | | `number` | `number` | The number value. | ### Children _This node has no children._ ## Functions ### `numberValueNode(number)` Helper function that creates a `NumberValueNode` object from any `number`. ```ts const node = numberValueNode(42); ``` ================================================ FILE: packages/nodes/docs/valueNodes/PublicKeyValueNode.md ================================================ # `PublicKeyValueNode` A node that represents the value of a 32-bytes public key. ## Attributes ### Data | Attribute | Type | Description | | ------------ | ---------------------- | -------------------------------------------- | | `kind` | `"publicKeyValueNode"` | The node discriminator. | | `publicKey` | `string` | The base58 encoded public key. | | `identifier` | `string` | (Optional) An identifier for the public key. | ### Children _This node has no children._ ## Functions ### `publicKeyValueNode(publicKey, identifier?)` Helper function that creates a `PublicKeyValueNode` object from a base58 encoded public key and an optional identifier. ```ts const node = publicKeyValueNode('7rA1KcBdW5hKmMasQdRVBFsD6T1nLtYuR6y59TJNgevR'); ``` ================================================ FILE: packages/nodes/docs/valueNodes/README.md ================================================ # `ValueNode` (abstract) The `ValueNode` type helper represents all the available value nodes. Note that `ValueNode` is a type alias and cannot be used directly as a node. Instead you may use one of the following nodes: - [`ArrayValueNode`](./ArrayValueNode.md) - [`BytesValueNode`](./BytesValueNode.md) - [`BooleanValueNode`](./BooleanValueNode.md) - [`ConstantValueNode`](./ConstantValueNode.md) - [`EnumValueNode`](./EnumValueNode.md) - [`MapValueNode`](./MapValueNode.md) - [`NoneValueNode`](./NoneValueNode.md) - [`NumberValueNode`](./NumberValueNode.md) - [`PublicKeyValueNode`](./PublicKeyValueNode.md) - [`SetValueNode`](./SetValueNode.md) - [`SomeValueNode`](./SomeValueNode.md) - [`StringValueNode`](./StringValueNode.md) - [`StructValueNode`](./StructValueNode.md) - [`TupleValueNode`](./TupleValueNode.md) ================================================ FILE: packages/nodes/docs/valueNodes/SetValueNode.md ================================================ # `SetValueNode` A node that represents a set of values — e.g. `{1, 2, 3}`. ## Attributes ### Data | Attribute | Type | Description | | --------- | ---------------- | ----------------------- | | `kind` | `"setValueNode"` | The node discriminator. | ### Children | Attribute | Type | Description | | --------- | ---------------------------- | ---------------------------------- | | `items` | [`ValueNode`](./README.md)[] | The value of all items in the set. | ## Functions ### `setValueNode(items)` Helper function that creates a `SetValueNode` object from an array of value nodes. ```ts const node = setValueNode([numberValueNode(1), numberValueNode(2), numberValueNode(3)]); ``` ================================================ FILE: packages/nodes/docs/valueNodes/SomeValueNode.md ================================================ # `SomeValueNode` A node that represents the presence of a value. For instance, this could be set as a default value for a field of type [`OptionTypeNode`](../typeNodes/OptionTypeNode.md). ## Attributes ### Data | Attribute | Type | Description | | --------- | ----------------- | ----------------------- | | `kind` | `"someValueNode"` | The node discriminator. | ### Children | Attribute | Type | Description | | --------- | -------------------------- | ------------------------------------ | | `value` | [`ValueNode`](./README.md) | The value that is marked as present. | ## Functions ### `someValueNode(value)` Helper function that creates a `SomeValueNode` object from a value node ```ts const node = someValueNode(numberValueNode(42)); ``` ================================================ FILE: packages/nodes/docs/valueNodes/StringValueNode.md ================================================ # `StringValueNode` A node that represents a string value — e.g. `"Hello"`. ## Attributes ### Data | Attribute | Type | Description | | --------- | ------------------- | ----------------------- | | `kind` | `"stringValueNode"` | The node discriminator. | | `string` | `string` | The string value. | ### Children _This node has no children._ ## Functions ### `stringValueNode(string)` Helper function that creates a `StringValueNode` object from a string value. ```ts const node = stringValueNode('Hello'); ``` ================================================ FILE: packages/nodes/docs/valueNodes/StructFieldValueNode.md ================================================ # `StructFieldValueNode` A node that represents a field value in a struct — e.g. `age: 42`. ## Attributes ### Data | Attribute | Type | Description | | --------- | ------------------------ | ----------------------- | | `kind` | `"structFieldValueNode"` | The node discriminator. | | `name` | `CamelCaseString` | The name of the field. | ### Children | Attribute | Type | Description | | --------- | -------------------------- | ----------------------- | | `value` | [`ValueNode`](./README.md) | The value of the field. | ## Functions ### `structFieldValueNode(name, value)` Helper function that creates a `StructFieldValueNode` object from a field name and a value node. ```ts const node = structFieldValueNode('age', numberValueNode(42)); ``` ================================================ FILE: packages/nodes/docs/valueNodes/StructValueNode.md ================================================ # `StructValueNode` A node that represents the value of a struct. ## Attributes ### Data | Attribute | Type | Description | | --------- | ------------------- | ----------------------- | | `kind` | `"structValueNode"` | The node discriminator. | ### Children | Attribute | Type | Description | | --------- | ----------------------------------------------------- | -------------------------------------- | | `fields` | [`StructFieldValueNode`](./StructFieldValueNode.md)[] | The value of all fields in the struct. | ## Functions ### `structValueNode(fields)` Helper function that creates a `StructValueNode` object from an array of field value nodes. ```ts const node = structValueNode([ structFieldValueNode('name', stringValueNode('Alice')), structFieldValueNode('age', numberValueNode(42)), ]); ``` ================================================ FILE: packages/nodes/docs/valueNodes/TupleValueNode.md ================================================ # `TupleValueNode` A node that represents the value of a tuple — e.g. `("Alice", 42)`. ## Attributes ### Data | Attribute | Type | Description | | --------- | ------------------ | ----------------------- | | `kind` | `"tupleValueNode"` | The node discriminator. | ### Children | Attribute | Type | Description | | --------- | ---------------------------- | ------------------------------------ | | `items` | [`ValueNode`](./README.md)[] | The value of all items in the tuple. | ## Functions ### `tupleValueNode(items)` Helper function that creates a `TupleValueNode` object from an array of value nodes. ```ts const node = tupleValueNode([stringValueNode('Alice'), numberValueNode(42)]); ``` ================================================ FILE: packages/nodes/package.json ================================================ { "name": "@codama/nodes", "version": "1.6.0", "description": "Node specifications and helpers for the Codama standard", "exports": { "types": "./dist/types/index.d.ts", "react-native": "./dist/index.react-native.mjs", "browser": { "import": "./dist/index.browser.mjs", "require": "./dist/index.browser.cjs" }, "node": { "import": "./dist/index.node.mjs", "require": "./dist/index.node.cjs" } }, "browser": { "./dist/index.node.cjs": "./dist/index.browser.cjs", "./dist/index.node.mjs": "./dist/index.browser.mjs" }, "main": "./dist/index.node.cjs", "module": "./dist/index.node.mjs", "react-native": "./dist/index.react-native.mjs", "types": "./dist/types/index.d.ts", "type": "commonjs", "files": [ "./dist/types", "./dist/index.*" ], "sideEffects": false, "keywords": [ "solana", "framework", "standard", "specifications" ], "scripts": { "build": "rimraf dist && tsup && tsc -p ./tsconfig.declarations.json", "dev": "vitest --project node", "lint": "eslint . && prettier --check .", "lint:fix": "eslint --fix . && prettier --write .", "test": "pnpm test:types && pnpm test:treeshakability && pnpm test:unit", "test:treeshakability": "for file in dist/index.*.mjs; do agadoo $file; done", "test:types": "tsc --noEmit", "test:unit": "vitest run" }, "dependencies": { "@codama/errors": "workspace:*", "@codama/node-types": "workspace:*" }, "license": "MIT", "repository": { "type": "git", "url": "https://github.com/codama-idl/codama" }, "bugs": { "url": "http://github.com/codama-idl/codama/issues" }, "browserslist": [ "supports bigint and not dead", "maintained node versions" ] } ================================================ FILE: packages/nodes/src/AccountNode.ts ================================================ import type { AccountNode, DiscriminatorNode, NestedTypeNode, PdaLinkNode, StructTypeNode } from '@codama/node-types'; import { camelCase, DocsInput, parseDocs } from './shared'; import { structTypeNode } from './typeNodes'; export type AccountNodeInput< TData extends NestedTypeNode = NestedTypeNode, TPda extends PdaLinkNode | undefined = PdaLinkNode | undefined, TDiscriminators extends DiscriminatorNode[] | undefined = DiscriminatorNode[] | undefined, > = Omit, 'data' | 'docs' | 'kind' | 'name'> & { readonly data?: TData; readonly docs?: DocsInput; readonly name: string; }; export function accountNode< TData extends NestedTypeNode = StructTypeNode<[]>, TPda extends PdaLinkNode | undefined = undefined, const TDiscriminators extends DiscriminatorNode[] | undefined = undefined, >(input: AccountNodeInput): AccountNode { return Object.freeze({ kind: 'accountNode', // Data. name: camelCase(input.name), ...(input.size === undefined ? {} : { size: input.size }), docs: parseDocs(input.docs), // Children. data: (input.data ?? structTypeNode([])) as TData, ...(input.pda !== undefined && { pda: input.pda }), ...(input.discriminators !== undefined && { discriminators: input.discriminators }), }); } ================================================ FILE: packages/nodes/src/DefinedTypeNode.ts ================================================ import type { DefinedTypeNode, TypeNode } from '@codama/node-types'; import { camelCase, DocsInput, parseDocs } from './shared'; export type DefinedTypeNodeInput = Omit< DefinedTypeNode, 'docs' | 'kind' | 'name' > & { readonly docs?: DocsInput; readonly name: string; }; export function definedTypeNode(input: DefinedTypeNodeInput): DefinedTypeNode { return Object.freeze({ kind: 'definedTypeNode', // Data. name: camelCase(input.name), docs: parseDocs(input.docs), // Children. type: input.type, }); } ================================================ FILE: packages/nodes/src/ErrorNode.ts ================================================ import type { ErrorNode } from '@codama/node-types'; import { camelCase, DocsInput, parseDocs } from './shared'; export type ErrorNodeInput = Omit & { readonly docs?: DocsInput; readonly name: string; }; export function errorNode(input: ErrorNodeInput): ErrorNode { return Object.freeze({ kind: 'errorNode', // Data. name: camelCase(input.name), code: input.code, message: input.message, docs: parseDocs(input.docs), }); } ================================================ FILE: packages/nodes/src/EventNode.ts ================================================ import type { DiscriminatorNode, EventNode, TypeNode } from '@codama/node-types'; import { camelCase, DocsInput, parseDocs } from './shared'; import { structTypeNode } from './typeNodes'; export type EventNodeInput< TData extends TypeNode = TypeNode, TDiscriminators extends DiscriminatorNode[] | undefined = DiscriminatorNode[] | undefined, > = Omit, 'docs' | 'kind' | 'name'> & { readonly docs?: DocsInput; readonly name: string; }; export function eventNode< TData extends TypeNode = ReturnType, const TDiscriminators extends DiscriminatorNode[] | undefined = undefined, >(input: EventNodeInput): EventNode { return Object.freeze({ kind: 'eventNode', // Data. name: camelCase(input.name), docs: parseDocs(input.docs), // Children. data: input.data, ...(input.discriminators !== undefined && { discriminators: input.discriminators }), }); } ================================================ FILE: packages/nodes/src/InstructionAccountNode.ts ================================================ import type { InstructionAccountNode, InstructionInputValueNode } from '@codama/node-types'; import { camelCase, DocsInput, parseDocs } from './shared'; export type InstructionAccountNodeInput< TDefaultValue extends InstructionInputValueNode | undefined = InstructionInputValueNode | undefined, > = Omit, 'docs' | 'isOptional' | 'kind' | 'name'> & { readonly docs?: DocsInput; readonly isOptional?: boolean; readonly name: string; }; export function instructionAccountNode( input: InstructionAccountNodeInput, ): InstructionAccountNode { return Object.freeze({ kind: 'instructionAccountNode', // Data. name: camelCase(input.name), isWritable: input.isWritable, isSigner: input.isSigner, isOptional: input.isOptional ?? false, docs: parseDocs(input.docs), // Children. ...(input.defaultValue !== undefined && { defaultValue: input.defaultValue }), }); } ================================================ FILE: packages/nodes/src/InstructionArgumentNode.ts ================================================ import type { InstructionArgumentNode, InstructionInputValueNode } from '@codama/node-types'; import { isNode } from './Node'; import { camelCase, DocsInput, parseDocs } from './shared'; import { structFieldTypeNode } from './typeNodes/StructFieldTypeNode'; import { structTypeNode } from './typeNodes/StructTypeNode'; import { VALUE_NODES } from './valueNodes'; export type InstructionArgumentNodeInput< TDefaultValue extends InstructionInputValueNode | undefined = InstructionInputValueNode | undefined, > = Omit, 'docs' | 'kind' | 'name'> & { readonly docs?: DocsInput; readonly name: string; }; export function instructionArgumentNode( input: InstructionArgumentNodeInput, ): InstructionArgumentNode { return Object.freeze({ kind: 'instructionArgumentNode', // Data. name: camelCase(input.name), ...(input.defaultValueStrategy !== undefined && { defaultValueStrategy: input.defaultValueStrategy }), docs: parseDocs(input.docs), // Children. type: input.type, ...(input.defaultValue !== undefined && { defaultValue: input.defaultValue }), }); } export function structTypeNodeFromInstructionArgumentNodes(nodes: InstructionArgumentNode[]) { return structTypeNode(nodes.map(structFieldTypeNodeFromInstructionArgumentNode)); } export function structFieldTypeNodeFromInstructionArgumentNode(node: InstructionArgumentNode) { if (isNode(node.defaultValue, VALUE_NODES)) { return structFieldTypeNode({ ...node, defaultValue: node.defaultValue }); } return structFieldTypeNode({ ...node, defaultValue: undefined, defaultValueStrategy: undefined, }); } ================================================ FILE: packages/nodes/src/InstructionByteDeltaNode.ts ================================================ import type { InstructionByteDeltaNode } from '@codama/node-types'; import { isNode } from './Node'; export function instructionByteDeltaNode( value: TValue, options: { subtract?: boolean; withHeader?: boolean; } = {}, ): InstructionByteDeltaNode { return Object.freeze({ kind: 'instructionByteDeltaNode', // Data. withHeader: options.withHeader ?? !isNode(value, 'resolverValueNode'), ...(options.subtract !== undefined && { subtract: options.subtract }), // Children. value, }); } ================================================ FILE: packages/nodes/src/InstructionNode.ts ================================================ import type { DiscriminatorNode, InstructionAccountNode, InstructionArgumentNode, InstructionByteDeltaNode, InstructionNode, InstructionRemainingAccountsNode, OptionalAccountStrategy, ProgramNode, RootNode, } from '@codama/node-types'; import { isNode } from './Node'; import { getAllInstructions } from './ProgramNode'; import { camelCase, DocsInput, parseDocs } from './shared'; type SubInstructionNode = InstructionNode; export type InstructionNodeInput< TAccounts extends InstructionAccountNode[] = InstructionAccountNode[], TArguments extends InstructionArgumentNode[] = InstructionArgumentNode[], TExtraArguments extends InstructionArgumentNode[] | undefined = InstructionArgumentNode[] | undefined, TRemainingAccounts extends InstructionRemainingAccountsNode[] | undefined = | InstructionRemainingAccountsNode[] | undefined, TByteDeltas extends InstructionByteDeltaNode[] | undefined = InstructionByteDeltaNode[] | undefined, TDiscriminators extends DiscriminatorNode[] | undefined = DiscriminatorNode[] | undefined, TSubInstructions extends SubInstructionNode[] | undefined = SubInstructionNode[] | undefined, > = Omit< Partial< InstructionNode< TAccounts, TArguments, TExtraArguments, TRemainingAccounts, TByteDeltas, TDiscriminators, TSubInstructions > >, 'docs' | 'kind' | 'name' > & { readonly docs?: DocsInput; readonly name: string; }; export function instructionNode< const TAccounts extends InstructionAccountNode[] = [], const TArguments extends InstructionArgumentNode[] = [], const TExtraArguments extends InstructionArgumentNode[] | undefined = undefined, const TRemainingAccounts extends InstructionRemainingAccountsNode[] | undefined = undefined, const TByteDeltas extends InstructionByteDeltaNode[] | undefined = undefined, const TDiscriminators extends DiscriminatorNode[] | undefined = undefined, const TSubInstructions extends SubInstructionNode[] | undefined = undefined, >( input: InstructionNodeInput< TAccounts, TArguments, TExtraArguments, TRemainingAccounts, TByteDeltas, TDiscriminators, TSubInstructions >, ): InstructionNode< TAccounts, TArguments, TExtraArguments, TRemainingAccounts, TByteDeltas, TDiscriminators, TSubInstructions > { return Object.freeze({ kind: 'instructionNode', // Data. name: camelCase(input.name), docs: parseDocs(input.docs), optionalAccountStrategy: parseOptionalAccountStrategy(input.optionalAccountStrategy), ...(input.status !== undefined && { status: input.status }), // Children. accounts: (input.accounts ?? []) as TAccounts, arguments: (input.arguments ?? []) as TArguments, extraArguments: input.extraArguments, remainingAccounts: input.remainingAccounts, byteDeltas: input.byteDeltas, discriminators: input.discriminators, subInstructions: input.subInstructions, }); } export function parseOptionalAccountStrategy( optionalAccountStrategy: OptionalAccountStrategy | undefined, ): OptionalAccountStrategy { return optionalAccountStrategy ?? 'programId'; } export function getAllInstructionArguments(node: InstructionNode): InstructionArgumentNode[] { return [...node.arguments, ...(node.extraArguments ?? [])]; } export function getAllInstructionsWithSubs( node: InstructionNode | ProgramNode | RootNode, config: { leavesOnly?: boolean; subInstructionsFirst?: boolean } = {}, ): InstructionNode[] { const { leavesOnly = false, subInstructionsFirst = false } = config; if (isNode(node, 'instructionNode')) { if (!node.subInstructions || node.subInstructions.length === 0) return [node]; const subInstructions = node.subInstructions.flatMap(sub => getAllInstructionsWithSubs(sub, config)); if (leavesOnly) return subInstructions; return subInstructionsFirst ? [...subInstructions, node] : [node, ...subInstructions]; } const instructions = isNode(node, 'programNode') ? node.instructions : getAllInstructions(node); return instructions.flatMap(instruction => getAllInstructionsWithSubs(instruction, config)); } ================================================ FILE: packages/nodes/src/InstructionRemainingAccountsNode.ts ================================================ import type { ArgumentValueNode, InstructionRemainingAccountsNode, ResolverValueNode } from '@codama/node-types'; import { DocsInput, parseDocs } from './shared'; export function instructionRemainingAccountsNode( value: TValue, options: { docs?: DocsInput; isOptional?: boolean; isSigner?: boolean | 'either'; isWritable?: boolean; } = {}, ): InstructionRemainingAccountsNode { return Object.freeze({ kind: 'instructionRemainingAccountsNode', // Data. ...(options.isOptional !== undefined && { isOptional: options.isOptional }), ...(options.isSigner !== undefined && { isSigner: options.isSigner }), ...(options.isWritable !== undefined && { isWritable: options.isWritable }), docs: parseDocs(options.docs), // Children. value, }); } ================================================ FILE: packages/nodes/src/InstructionStatusNode.ts ================================================ import type { InstructionLifecycle, InstructionStatusNode } from '@codama/node-types'; export function instructionStatusNode(lifecycle: InstructionLifecycle, message?: string): InstructionStatusNode { return Object.freeze({ kind: 'instructionStatusNode', // Data. lifecycle, ...(message !== undefined && { message }), }); } ================================================ FILE: packages/nodes/src/Node.ts ================================================ import { CODAMA_ERROR__UNEXPECTED_NODE_KIND, CodamaError } from '@codama/errors'; import type { GetNodeFromKind, Node, NodeKind } from '@codama/node-types'; import { REGISTERED_CONTEXTUAL_VALUE_NODE_KINDS } from './contextualValueNodes/ContextualValueNode'; import { REGISTERED_COUNT_NODE_KINDS } from './countNodes/CountNode'; import { REGISTERED_DISCRIMINATOR_NODE_KINDS } from './discriminatorNodes/DiscriminatorNode'; import { REGISTERED_LINK_NODE_KINDS } from './linkNodes/LinkNode'; import { REGISTERED_PDA_SEED_NODE_KINDS } from './pdaSeedNodes/PdaSeedNode'; import { REGISTERED_TYPE_NODE_KINDS } from './typeNodes/TypeNode'; import { REGISTERED_VALUE_NODE_KINDS } from './valueNodes/ValueNode'; // Node Registration. export const REGISTERED_NODE_KINDS = [ ...REGISTERED_CONTEXTUAL_VALUE_NODE_KINDS, ...REGISTERED_DISCRIMINATOR_NODE_KINDS, ...REGISTERED_LINK_NODE_KINDS, ...REGISTERED_PDA_SEED_NODE_KINDS, ...REGISTERED_COUNT_NODE_KINDS, ...REGISTERED_TYPE_NODE_KINDS, ...REGISTERED_VALUE_NODE_KINDS, 'rootNode' as const, 'programNode' as const, 'pdaNode' as const, 'accountNode' as const, 'eventNode' as const, 'instructionAccountNode' as const, 'instructionArgumentNode' as const, 'instructionByteDeltaNode' as const, 'instructionNode' as const, 'instructionRemainingAccountsNode' as const, 'instructionStatusNode' as const, 'errorNode' as const, 'definedTypeNode' as const, ]; // Node Helpers. export function isNode( node: Node | null | undefined, kind: TKind | TKind[], ): node is GetNodeFromKind { const kinds = Array.isArray(kind) ? kind : [kind]; return !!node && (kinds as NodeKind[]).includes(node.kind); } export function assertIsNode( node: Node | null | undefined, kind: TKind | TKind[], ): asserts node is GetNodeFromKind { const kinds = Array.isArray(kind) ? kind : [kind]; if (!isNode(node, kinds)) { throw new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, { expectedKinds: kinds, kind: node?.kind ?? null, node, }); } } export function isNodeFilter( kind: TKind | TKind[], ): (node: Node | null | undefined) => node is GetNodeFromKind { return (node): node is GetNodeFromKind => isNode(node, kind); } export function assertIsNodeFilter( kind: TKind | TKind[], ): (node: Node | null | undefined) => node is GetNodeFromKind { return (node): node is GetNodeFromKind => { assertIsNode(node, kind); return true; }; } export function removeNullAndAssertIsNodeFilter( kind: TKind | TKind[], ): (node: Node | null | undefined) => node is GetNodeFromKind { return (node): node is GetNodeFromKind => { if (node) assertIsNode(node, kind); return node != null; }; } ================================================ FILE: packages/nodes/src/PdaNode.ts ================================================ import type { PdaNode, PdaSeedNode } from '@codama/node-types'; import { camelCase, DocsInput, parseDocs } from './shared'; export type PdaNodeInput = Omit< PdaNode, 'docs' | 'kind' | 'name' > & { readonly docs?: DocsInput; readonly name: string; }; export function pdaNode(input: PdaNodeInput): PdaNode { return Object.freeze({ kind: 'pdaNode', // Data. name: camelCase(input.name), docs: parseDocs(input.docs), ...(input.programId && { programId: input.programId }), // Children. seeds: input.seeds, }); } ================================================ FILE: packages/nodes/src/ProgramNode.ts ================================================ import type { AccountNode, DefinedTypeNode, ErrorNode, EventNode, InstructionNode, PdaNode, ProgramNode, RootNode, } from '@codama/node-types'; import { camelCase, DocsInput, parseDocs } from './shared'; export type ProgramNodeInput< TPdas extends PdaNode[] = PdaNode[], TAccounts extends AccountNode[] = AccountNode[], TInstructions extends InstructionNode[] = InstructionNode[], TDefinedTypes extends DefinedTypeNode[] = DefinedTypeNode[], TErrors extends ErrorNode[] = ErrorNode[], TEvents extends EventNode[] = EventNode[], > = Omit< Partial>, 'docs' | 'kind' | 'name' | 'publicKey' > & { readonly docs?: DocsInput; readonly name: string; readonly publicKey: ProgramNode['publicKey']; }; export function programNode< const TPdas extends PdaNode[] = [], const TAccounts extends AccountNode[] = [], const TInstructions extends InstructionNode[] = [], const TDefinedTypes extends DefinedTypeNode[] = [], const TErrors extends ErrorNode[] = [], const TEvents extends EventNode[] = [], >( input: ProgramNodeInput, ): ProgramNode { return Object.freeze({ kind: 'programNode', // Data. name: camelCase(input.name), publicKey: input.publicKey, version: input.version ?? '0.0.0', ...(input.origin !== undefined && { origin: input.origin }), docs: parseDocs(input.docs), // Children. accounts: (input.accounts ?? []) as TAccounts, instructions: (input.instructions ?? []) as TInstructions, definedTypes: (input.definedTypes ?? []) as TDefinedTypes, pdas: (input.pdas ?? []) as TPdas, events: (input.events ?? []) as TEvents, errors: (input.errors ?? []) as TErrors, }); } export function getAllPrograms(node: ProgramNode | ProgramNode[] | RootNode): ProgramNode[] { if (Array.isArray(node)) return node; if (node.kind === 'programNode') return [node]; return [node.program, ...node.additionalPrograms]; } export function getAllPdas(node: ProgramNode | ProgramNode[] | RootNode): PdaNode[] { return getAllPrograms(node).flatMap(program => program.pdas); } export function getAllAccounts(node: ProgramNode | ProgramNode[] | RootNode): AccountNode[] { return getAllPrograms(node).flatMap(program => program.accounts); } export function getAllEvents(node: ProgramNode | ProgramNode[] | RootNode): EventNode[] { return getAllPrograms(node).flatMap(program => program.events); } export function getAllDefinedTypes(node: ProgramNode | ProgramNode[] | RootNode): DefinedTypeNode[] { return getAllPrograms(node).flatMap(program => program.definedTypes); } export function getAllInstructions(node: ProgramNode | ProgramNode[] | RootNode): InstructionNode[] { return getAllPrograms(node).flatMap(program => program.instructions); } export function getAllErrors(node: ProgramNode | ProgramNode[] | RootNode): ErrorNode[] { return getAllPrograms(node).flatMap(program => program.errors); } ================================================ FILE: packages/nodes/src/RootNode.ts ================================================ import type { CodamaVersion, ProgramNode, RootNode } from '@codama/node-types'; export function rootNode( program: TProgram, additionalPrograms?: TAdditionalPrograms, ): RootNode { return Object.freeze({ kind: 'rootNode', // Data. standard: 'codama', version: __VERSION__ as CodamaVersion, // Children. program, additionalPrograms: (additionalPrograms ?? []) as TAdditionalPrograms, }); } ================================================ FILE: packages/nodes/src/contextualValueNodes/AccountBumpValueNode.ts ================================================ import type { AccountBumpValueNode } from '@codama/node-types'; import { camelCase } from '../shared'; export function accountBumpValueNode(name: string): AccountBumpValueNode { return Object.freeze({ kind: 'accountBumpValueNode', // Data. name: camelCase(name), }); } ================================================ FILE: packages/nodes/src/contextualValueNodes/AccountValueNode.ts ================================================ import type { AccountValueNode } from '@codama/node-types'; import { camelCase } from '../shared'; export function accountValueNode(name: string): AccountValueNode { return Object.freeze({ kind: 'accountValueNode', // Data. name: camelCase(name), }); } ================================================ FILE: packages/nodes/src/contextualValueNodes/ArgumentValueNode.ts ================================================ import type { ArgumentValueNode } from '@codama/node-types'; import { camelCase } from '../shared'; export function argumentValueNode(name: string): ArgumentValueNode { return Object.freeze({ kind: 'argumentValueNode', // Data. name: camelCase(name), }); } ================================================ FILE: packages/nodes/src/contextualValueNodes/ConditionalValueNode.ts ================================================ import type { AccountValueNode, ArgumentValueNode, ConditionalValueNode, InstructionInputValueNode, ResolverValueNode, ValueNode, } from '@codama/node-types'; type ConditionNode = AccountValueNode | ArgumentValueNode | ResolverValueNode; export function conditionalValueNode< TCondition extends ConditionNode, TValue extends ValueNode | undefined = undefined, TIfTrue extends InstructionInputValueNode | undefined = undefined, TIfFalse extends InstructionInputValueNode | undefined = undefined, >(input: { condition: TCondition; ifFalse?: TIfFalse; ifTrue?: TIfTrue; value?: TValue; }): ConditionalValueNode { return Object.freeze({ kind: 'conditionalValueNode', // Children. condition: input.condition, ...(input.value !== undefined && { value: input.value }), ...(input.ifTrue !== undefined && { ifTrue: input.ifTrue }), ...(input.ifFalse !== undefined && { ifFalse: input.ifFalse }), }); } ================================================ FILE: packages/nodes/src/contextualValueNodes/ContextualValueNode.ts ================================================ import { VALUE_NODES } from '../valueNodes/ValueNode'; // Standalone Contextual Value Node Registration. export const STANDALONE_CONTEXTUAL_VALUE_NODE_KINDS = [ 'accountBumpValueNode' as const, 'accountValueNode' as const, 'argumentValueNode' as const, 'conditionalValueNode' as const, 'identityValueNode' as const, 'payerValueNode' as const, 'pdaValueNode' as const, 'programIdValueNode' as const, 'resolverValueNode' as const, ]; // Contextual Value Node Registration. export const REGISTERED_CONTEXTUAL_VALUE_NODE_KINDS = [ ...STANDALONE_CONTEXTUAL_VALUE_NODE_KINDS, 'pdaSeedValueNode' as const, ]; // Contextual Value Node Helpers. export const CONTEXTUAL_VALUE_NODES = STANDALONE_CONTEXTUAL_VALUE_NODE_KINDS; export const INSTRUCTION_INPUT_VALUE_NODES = [...VALUE_NODES, ...CONTEXTUAL_VALUE_NODES, 'programLinkNode' as const]; ================================================ FILE: packages/nodes/src/contextualValueNodes/IdentityValueNode.ts ================================================ import type { IdentityValueNode } from '@codama/node-types'; export function identityValueNode(): IdentityValueNode { return Object.freeze({ kind: 'identityValueNode' }); } ================================================ FILE: packages/nodes/src/contextualValueNodes/PayerValueNode.ts ================================================ import type { PayerValueNode } from '@codama/node-types'; export function payerValueNode(): PayerValueNode { return Object.freeze({ kind: 'payerValueNode' }); } ================================================ FILE: packages/nodes/src/contextualValueNodes/PdaSeedValueNode.ts ================================================ import type { AccountValueNode, ArgumentValueNode, PdaSeedValueNode, ValueNode } from '@codama/node-types'; import { camelCase } from '../shared'; export function pdaSeedValueNode< TValue extends AccountValueNode | ArgumentValueNode | ValueNode = AccountValueNode | ArgumentValueNode | ValueNode, >(name: string, value: TValue): PdaSeedValueNode { return Object.freeze({ kind: 'pdaSeedValueNode', // Data. name: camelCase(name), // Children. value, }); } ================================================ FILE: packages/nodes/src/contextualValueNodes/PdaValueNode.ts ================================================ import type { AccountValueNode, ArgumentValueNode, PdaLinkNode, PdaNode, PdaSeedValueNode, PdaValueNode, } from '@codama/node-types'; import { pdaLinkNode } from '../linkNodes'; export function pdaValueNode< const TSeeds extends PdaSeedValueNode[] = [], const TProgram extends AccountValueNode | ArgumentValueNode | undefined = undefined, >( pda: PdaLinkNode | PdaNode | string, seeds: TSeeds = [] as PdaSeedValueNode[] as TSeeds, programId: TProgram = undefined as TProgram, ): PdaValueNode { return Object.freeze({ kind: 'pdaValueNode', // Children. pda: typeof pda === 'string' ? pdaLinkNode(pda) : pda, seeds, ...(programId ? { programId } : {}), }); } ================================================ FILE: packages/nodes/src/contextualValueNodes/ProgramIdValueNode.ts ================================================ import type { ProgramIdValueNode } from '@codama/node-types'; export function programIdValueNode(): ProgramIdValueNode { return Object.freeze({ kind: 'programIdValueNode' }); } ================================================ FILE: packages/nodes/src/contextualValueNodes/ResolverValueNode.ts ================================================ import type { AccountValueNode, ArgumentValueNode, ResolverValueNode } from '@codama/node-types'; import { camelCase, DocsInput, parseDocs } from '../shared'; export function resolverValueNode( name: string, options: { dependsOn?: TDependsOn; docs?: DocsInput; } = {}, ): ResolverValueNode { return Object.freeze({ kind: 'resolverValueNode', // Data. name: camelCase(name), docs: parseDocs(options.docs), // Children. dependsOn: options.dependsOn, }); } ================================================ FILE: packages/nodes/src/contextualValueNodes/index.ts ================================================ export * from './AccountBumpValueNode'; export * from './AccountValueNode'; export * from './ArgumentValueNode'; export * from './ConditionalValueNode'; export * from './ContextualValueNode'; export * from './IdentityValueNode'; export * from './PayerValueNode'; export * from './PdaSeedValueNode'; export * from './PdaValueNode'; export * from './ProgramIdValueNode'; export * from './ResolverValueNode'; ================================================ FILE: packages/nodes/src/countNodes/CountNode.ts ================================================ // Count Node Registration. export const REGISTERED_COUNT_NODE_KINDS = [ 'fixedCountNode' as const, 'remainderCountNode' as const, 'prefixedCountNode' as const, ]; // Count Node Helpers. export const COUNT_NODES = REGISTERED_COUNT_NODE_KINDS; ================================================ FILE: packages/nodes/src/countNodes/FixedCountNode.ts ================================================ import type { FixedCountNode } from '@codama/node-types'; export function fixedCountNode(value: number): FixedCountNode { return Object.freeze({ kind: 'fixedCountNode', // Data. value, }); } ================================================ FILE: packages/nodes/src/countNodes/PrefixedCountNode.ts ================================================ import type { NestedTypeNode, NumberTypeNode, PrefixedCountNode } from '@codama/node-types'; export function prefixedCountNode>( prefix: TPrefix, ): PrefixedCountNode { return Object.freeze({ kind: 'prefixedCountNode', // Children. prefix, }); } ================================================ FILE: packages/nodes/src/countNodes/RemainderCountNode.ts ================================================ import type { RemainderCountNode } from '@codama/node-types'; export function remainderCountNode(): RemainderCountNode { return Object.freeze({ kind: 'remainderCountNode' }); } ================================================ FILE: packages/nodes/src/countNodes/index.ts ================================================ export * from './CountNode'; export * from './FixedCountNode'; export * from './PrefixedCountNode'; export * from './RemainderCountNode'; ================================================ FILE: packages/nodes/src/discriminatorNodes/ConstantDiscriminatorNode.ts ================================================ import type { ConstantDiscriminatorNode, ConstantValueNode } from '@codama/node-types'; export function constantDiscriminatorNode( constant: TConstant, offset: number = 0, ): ConstantDiscriminatorNode { return Object.freeze({ kind: 'constantDiscriminatorNode', // Data. offset, // Children. constant, }); } ================================================ FILE: packages/nodes/src/discriminatorNodes/DiscriminatorNode.ts ================================================ // Discriminator Node Registration. export const REGISTERED_DISCRIMINATOR_NODE_KINDS = [ 'constantDiscriminatorNode' as const, 'fieldDiscriminatorNode' as const, 'sizeDiscriminatorNode' as const, ]; // Discriminator Node Helpers. export const DISCRIMINATOR_NODES = REGISTERED_DISCRIMINATOR_NODE_KINDS; ================================================ FILE: packages/nodes/src/discriminatorNodes/FieldDiscriminatorNode.ts ================================================ import type { FieldDiscriminatorNode } from '@codama/node-types'; import { camelCase } from '../shared'; export function fieldDiscriminatorNode(name: string, offset: number = 0): FieldDiscriminatorNode { return Object.freeze({ kind: 'fieldDiscriminatorNode', // Data. name: camelCase(name), offset, }); } ================================================ FILE: packages/nodes/src/discriminatorNodes/SizeDiscriminatorNode.ts ================================================ import type { SizeDiscriminatorNode } from '@codama/node-types'; export function sizeDiscriminatorNode(size: number): SizeDiscriminatorNode { return Object.freeze({ kind: 'sizeDiscriminatorNode', // Data. size, }); } ================================================ FILE: packages/nodes/src/discriminatorNodes/index.ts ================================================ export * from './ConstantDiscriminatorNode'; export * from './DiscriminatorNode'; export * from './FieldDiscriminatorNode'; export * from './SizeDiscriminatorNode'; ================================================ FILE: packages/nodes/src/index.ts ================================================ export * from '@codama/node-types'; export * from './contextualValueNodes'; export * from './countNodes'; export * from './discriminatorNodes'; export * from './linkNodes'; export * from './pdaSeedNodes'; export * from './typeNodes'; export * from './valueNodes'; export * from './shared'; export * from './AccountNode'; export * from './DefinedTypeNode'; export * from './EventNode'; export * from './ErrorNode'; export * from './InstructionAccountNode'; export * from './InstructionArgumentNode'; export * from './InstructionByteDeltaNode'; export * from './InstructionNode'; export * from './InstructionRemainingAccountsNode'; export * from './InstructionStatusNode'; export * from './Node'; export * from './PdaNode'; export * from './ProgramNode'; export * from './RootNode'; ================================================ FILE: packages/nodes/src/linkNodes/AccountLinkNode.ts ================================================ import type { AccountLinkNode, ProgramLinkNode } from '@codama/node-types'; import { camelCase } from '../shared'; import { programLinkNode } from './ProgramLinkNode'; export function accountLinkNode(name: string, program?: ProgramLinkNode | string): AccountLinkNode { return Object.freeze({ kind: 'accountLinkNode', // Children. ...(program === undefined ? {} : { program: typeof program === 'string' ? programLinkNode(program) : program }), // Data. name: camelCase(name), }); } ================================================ FILE: packages/nodes/src/linkNodes/DefinedTypeLinkNode.ts ================================================ import type { DefinedTypeLinkNode, ProgramLinkNode } from '@codama/node-types'; import { camelCase } from '../shared'; import { programLinkNode } from './ProgramLinkNode'; export function definedTypeLinkNode(name: string, program?: ProgramLinkNode | string): DefinedTypeLinkNode { return Object.freeze({ kind: 'definedTypeLinkNode', // Children. ...(program === undefined ? {} : { program: typeof program === 'string' ? programLinkNode(program) : program }), // Data. name: camelCase(name), }); } ================================================ FILE: packages/nodes/src/linkNodes/InstructionAccountLinkNode.ts ================================================ import type { InstructionAccountLinkNode, InstructionLinkNode } from '@codama/node-types'; import { camelCase } from '../shared'; import { instructionLinkNode } from './InstructionLinkNode'; export function instructionAccountLinkNode( name: string, instruction?: InstructionLinkNode | string, ): InstructionAccountLinkNode { return Object.freeze({ kind: 'instructionAccountLinkNode', // Children. ...(instruction === undefined ? {} : { instruction: typeof instruction === 'string' ? instructionLinkNode(instruction) : instruction }), // Data. name: camelCase(name), }); } ================================================ FILE: packages/nodes/src/linkNodes/InstructionArgumentLinkNode.ts ================================================ import type { InstructionArgumentLinkNode, InstructionLinkNode } from '@codama/node-types'; import { camelCase } from '../shared'; import { instructionLinkNode } from './InstructionLinkNode'; export function instructionArgumentLinkNode( name: string, instruction?: InstructionLinkNode | string, ): InstructionArgumentLinkNode { return Object.freeze({ kind: 'instructionArgumentLinkNode', // Children. ...(instruction === undefined ? {} : { instruction: typeof instruction === 'string' ? instructionLinkNode(instruction) : instruction }), // Data. name: camelCase(name), }); } ================================================ FILE: packages/nodes/src/linkNodes/InstructionLinkNode.ts ================================================ import type { InstructionLinkNode, ProgramLinkNode } from '@codama/node-types'; import { camelCase } from '../shared'; import { programLinkNode } from './ProgramLinkNode'; export function instructionLinkNode(name: string, program?: ProgramLinkNode | string): InstructionLinkNode { return Object.freeze({ kind: 'instructionLinkNode', // Children. ...(program === undefined ? {} : { program: typeof program === 'string' ? programLinkNode(program) : program }), // Data. name: camelCase(name), }); } ================================================ FILE: packages/nodes/src/linkNodes/LinkNode.ts ================================================ // Link Node Registration. export const REGISTERED_LINK_NODE_KINDS = [ 'accountLinkNode' as const, 'definedTypeLinkNode' as const, 'instructionAccountLinkNode' as const, 'instructionArgumentLinkNode' as const, 'instructionLinkNode' as const, 'pdaLinkNode' as const, 'programLinkNode' as const, ]; // Link Node Helpers. export const LINK_NODES = REGISTERED_LINK_NODE_KINDS; ================================================ FILE: packages/nodes/src/linkNodes/PdaLinkNode.ts ================================================ import type { PdaLinkNode, ProgramLinkNode } from '@codama/node-types'; import { camelCase } from '../shared'; import { programLinkNode } from './ProgramLinkNode'; export function pdaLinkNode(name: string, program?: ProgramLinkNode | string): PdaLinkNode { return Object.freeze({ kind: 'pdaLinkNode', // Children. ...(program === undefined ? {} : { program: typeof program === 'string' ? programLinkNode(program) : program }), // Data. name: camelCase(name), }); } ================================================ FILE: packages/nodes/src/linkNodes/ProgramLinkNode.ts ================================================ import type { ProgramLinkNode } from '@codama/node-types'; import { camelCase } from '../shared'; export function programLinkNode(name: string): ProgramLinkNode { return Object.freeze({ kind: 'programLinkNode', // Data. name: camelCase(name), }); } ================================================ FILE: packages/nodes/src/linkNodes/index.ts ================================================ export * from './AccountLinkNode'; export * from './DefinedTypeLinkNode'; export * from './InstructionAccountLinkNode'; export * from './InstructionArgumentLinkNode'; export * from './InstructionLinkNode'; export * from './LinkNode'; export * from './PdaLinkNode'; export * from './ProgramLinkNode'; ================================================ FILE: packages/nodes/src/pdaSeedNodes/ConstantPdaSeedNode.ts ================================================ import type { BytesEncoding, ConstantPdaSeedNode, ProgramIdValueNode, TypeNode, ValueNode } from '@codama/node-types'; import { programIdValueNode } from '../contextualValueNodes/ProgramIdValueNode'; import { bytesTypeNode } from '../typeNodes/BytesTypeNode'; import { publicKeyTypeNode } from '../typeNodes/PublicKeyTypeNode'; import { stringTypeNode } from '../typeNodes/StringTypeNode'; import { bytesValueNode } from '../valueNodes/BytesValueNode'; import { stringValueNode } from '../valueNodes/StringValueNode'; export function constantPdaSeedNode( type: TType, value: TValue, ): ConstantPdaSeedNode { return Object.freeze({ kind: 'constantPdaSeedNode', // Children. type, value, }); } export function constantPdaSeedNodeFromProgramId() { return constantPdaSeedNode(publicKeyTypeNode(), programIdValueNode()); } export function constantPdaSeedNodeFromString(encoding: TEncoding, string: string) { return constantPdaSeedNode(stringTypeNode(encoding), stringValueNode(string)); } export function constantPdaSeedNodeFromBytes(encoding: TEncoding, data: string) { return constantPdaSeedNode(bytesTypeNode(), bytesValueNode(encoding, data)); } ================================================ FILE: packages/nodes/src/pdaSeedNodes/PdaSeedNode.ts ================================================ // Pda Seed Node Registration. export const REGISTERED_PDA_SEED_NODE_KINDS = ['constantPdaSeedNode' as const, 'variablePdaSeedNode' as const]; // Pda Seed Node Helpers. export const PDA_SEED_NODES = REGISTERED_PDA_SEED_NODE_KINDS; ================================================ FILE: packages/nodes/src/pdaSeedNodes/VariablePdaSeedNode.ts ================================================ import type { TypeNode, VariablePdaSeedNode } from '@codama/node-types'; import { camelCase, DocsInput, parseDocs } from '../shared'; export function variablePdaSeedNode( name: string, type: TType, docs?: DocsInput, ): VariablePdaSeedNode { return Object.freeze({ kind: 'variablePdaSeedNode', // Data. name: camelCase(name), docs: parseDocs(docs), // Children. type, }); } ================================================ FILE: packages/nodes/src/pdaSeedNodes/index.ts ================================================ export * from './ConstantPdaSeedNode'; export * from './PdaSeedNode'; export * from './VariablePdaSeedNode'; ================================================ FILE: packages/nodes/src/shared/docs.ts ================================================ import type { Docs } from '@codama/node-types'; export type DocsInput = string[] | string; export function parseDocs(docs: DocsInput | null | undefined): Docs { if (docs === null || docs === undefined) return []; return Array.isArray(docs) ? docs : [docs]; } ================================================ FILE: packages/nodes/src/shared/index.ts ================================================ export * from './docs'; export * from './stringCases'; ================================================ FILE: packages/nodes/src/shared/stringCases.ts ================================================ import type { CamelCaseString, KebabCaseString, PascalCaseString, SnakeCaseString, TitleCaseString, } from '@codama/node-types'; export function capitalize(str: string): string { if (str.length === 0) return str; return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase(); } export function titleCase(str: string): TitleCaseString { return str .replace(/([A-Z])/g, ' $1') .split(/[^a-zA-Z0-9]+/) .filter(word => word.length > 0) .map(capitalize) .join(' ') as TitleCaseString; } export function pascalCase(str: string): PascalCaseString { return titleCase(str).split(' ').join('') as PascalCaseString; } export function camelCase(str: string): CamelCaseString { if (str.length === 0) return str as CamelCaseString; const pascalStr = pascalCase(str); return (pascalStr.charAt(0).toLowerCase() + pascalStr.slice(1)) as CamelCaseString; } export function kebabCase(str: string): KebabCaseString { return titleCase(str).split(' ').join('-').toLowerCase() as KebabCaseString; } export function snakeCase(str: string): SnakeCaseString { return titleCase(str).split(' ').join('_').toLowerCase() as SnakeCaseString; } ================================================ FILE: packages/nodes/src/typeNodes/AmountTypeNode.ts ================================================ import type { AmountTypeNode, NestedTypeNode, NumberTypeNode } from '@codama/node-types'; export function amountTypeNode>( number: TNumber, decimals: number, unit?: string, ): AmountTypeNode { return Object.freeze({ kind: 'amountTypeNode', // Data. decimals, ...(unit !== undefined && { unit }), // Children. number, }); } ================================================ FILE: packages/nodes/src/typeNodes/ArrayTypeNode.ts ================================================ import type { ArrayTypeNode, CountNode, TypeNode } from '@codama/node-types'; export function arrayTypeNode( item: TItem, count: TCount, ): ArrayTypeNode { return Object.freeze({ kind: 'arrayTypeNode', // Children. item, count, }); } ================================================ FILE: packages/nodes/src/typeNodes/BooleanTypeNode.ts ================================================ import type { BooleanTypeNode, NestedTypeNode, NumberTypeNode } from '@codama/node-types'; import { numberTypeNode } from './NumberTypeNode'; export function booleanTypeNode = NumberTypeNode<'u8'>>( size?: TSize, ): BooleanTypeNode { return Object.freeze({ kind: 'booleanTypeNode', // Children. size: (size ?? numberTypeNode('u8')) as TSize, }); } ================================================ FILE: packages/nodes/src/typeNodes/BytesTypeNode.ts ================================================ import type { BytesTypeNode } from '@codama/node-types'; export function bytesTypeNode(): BytesTypeNode { return Object.freeze({ kind: 'bytesTypeNode' }); } ================================================ FILE: packages/nodes/src/typeNodes/DateTimeTypeNode.ts ================================================ import type { DateTimeTypeNode, NestedTypeNode, NumberTypeNode } from '@codama/node-types'; export function dateTimeTypeNode = NestedTypeNode>( number: TNumber, ): DateTimeTypeNode { return Object.freeze({ kind: 'dateTimeTypeNode', // Children. number, }); } ================================================ FILE: packages/nodes/src/typeNodes/EnumEmptyVariantTypeNode.ts ================================================ import type { EnumEmptyVariantTypeNode } from '@codama/node-types'; import { camelCase } from '../shared'; export function enumEmptyVariantTypeNode(name: string, discriminator?: number): EnumEmptyVariantTypeNode { return Object.freeze({ kind: 'enumEmptyVariantTypeNode', // Data. name: camelCase(name), discriminator, }); } ================================================ FILE: packages/nodes/src/typeNodes/EnumStructVariantTypeNode.ts ================================================ import type { EnumStructVariantTypeNode, NestedTypeNode, StructTypeNode } from '@codama/node-types'; import { camelCase } from '../shared'; export function enumStructVariantTypeNode>( name: string, struct: TStruct, discriminator?: number, ): EnumStructVariantTypeNode { return Object.freeze({ kind: 'enumStructVariantTypeNode', // Data. name: camelCase(name), ...(discriminator !== undefined && { discriminator }), // Children. struct, }); } ================================================ FILE: packages/nodes/src/typeNodes/EnumTupleVariantTypeNode.ts ================================================ import type { EnumTupleVariantTypeNode, NestedTypeNode, TupleTypeNode } from '@codama/node-types'; import { camelCase } from '../shared'; export function enumTupleVariantTypeNode>( name: string, tuple: TTuple, discriminator?: number, ): EnumTupleVariantTypeNode { return Object.freeze({ kind: 'enumTupleVariantTypeNode', // Data. name: camelCase(name), ...(discriminator !== undefined && { discriminator }), // Children. tuple, }); } ================================================ FILE: packages/nodes/src/typeNodes/EnumTypeNode.ts ================================================ import type { EnumTypeNode, EnumVariantTypeNode, NestedTypeNode, NumberTypeNode } from '@codama/node-types'; import { numberTypeNode } from './NumberTypeNode'; export function enumTypeNode< const TVariants extends EnumVariantTypeNode[], TSize extends NestedTypeNode = NumberTypeNode<'u8'>, >(variants: TVariants, options: { size?: TSize } = {}): EnumTypeNode { return Object.freeze({ kind: 'enumTypeNode', // Children. variants, size: (options.size ?? numberTypeNode('u8')) as TSize, }); } export function isScalarEnum(node: EnumTypeNode): boolean { return node.variants.every(variant => variant.kind === 'enumEmptyVariantTypeNode'); } export function isDataEnum(node: EnumTypeNode): boolean { return !isScalarEnum(node); } ================================================ FILE: packages/nodes/src/typeNodes/EnumVariantTypeNode.ts ================================================ export const ENUM_VARIANT_TYPE_NODES = [ 'enumEmptyVariantTypeNode' as const, 'enumStructVariantTypeNode' as const, 'enumTupleVariantTypeNode' as const, ]; ================================================ FILE: packages/nodes/src/typeNodes/FixedSizeTypeNode.ts ================================================ import type { FixedSizeTypeNode, TypeNode } from '@codama/node-types'; export function fixedSizeTypeNode(type: TType, size: number): FixedSizeTypeNode { return Object.freeze({ kind: 'fixedSizeTypeNode', // Data. size, // Children. type, }); } ================================================ FILE: packages/nodes/src/typeNodes/HiddenPrefixTypeNode.ts ================================================ import type { ConstantValueNode, HiddenPrefixTypeNode, TypeNode } from '@codama/node-types'; export function hiddenPrefixTypeNode( type: TType, prefix: TPrefix, ): HiddenPrefixTypeNode { return Object.freeze({ kind: 'hiddenPrefixTypeNode', // Children. type, prefix, }); } ================================================ FILE: packages/nodes/src/typeNodes/HiddenSuffixTypeNode.ts ================================================ import type { ConstantValueNode, HiddenSuffixTypeNode, TypeNode } from '@codama/node-types'; export function hiddenSuffixTypeNode( type: TType, suffix: TSuffix, ): HiddenSuffixTypeNode { return Object.freeze({ kind: 'hiddenSuffixTypeNode', // Children. type, suffix, }); } ================================================ FILE: packages/nodes/src/typeNodes/MapTypeNode.ts ================================================ import type { CountNode, MapTypeNode, TypeNode } from '@codama/node-types'; export function mapTypeNode( key: TKey, value: TValue, count: TCount, ): MapTypeNode { return Object.freeze({ kind: 'mapTypeNode', // Children. key, value, count, }); } ================================================ FILE: packages/nodes/src/typeNodes/NestedTypeNode.ts ================================================ import { CODAMA_ERROR__UNEXPECTED_NESTED_NODE_KIND, CodamaError } from '@codama/errors'; import type { NestedTypeNode, Node, TypeNode } from '@codama/node-types'; import { isNode } from '../Node'; import { TYPE_NODES } from './TypeNode'; export function resolveNestedTypeNode(typeNode: NestedTypeNode): TType { switch (typeNode.kind) { case 'fixedSizeTypeNode': case 'hiddenPrefixTypeNode': case 'hiddenSuffixTypeNode': case 'postOffsetTypeNode': case 'preOffsetTypeNode': case 'sentinelTypeNode': case 'sizePrefixTypeNode': return resolveNestedTypeNode(typeNode.type as NestedTypeNode); default: return typeNode; } } export function transformNestedTypeNode( typeNode: NestedTypeNode, map: (type: TFrom) => TTo, ): NestedTypeNode { switch (typeNode.kind) { case 'fixedSizeTypeNode': case 'hiddenPrefixTypeNode': case 'hiddenSuffixTypeNode': case 'postOffsetTypeNode': case 'preOffsetTypeNode': case 'sentinelTypeNode': case 'sizePrefixTypeNode': return Object.freeze({ ...typeNode, type: transformNestedTypeNode(typeNode.type as NestedTypeNode, map), } as NestedTypeNode); default: return map(typeNode); } } export function isNestedTypeNode( node: Node | null | undefined, kind: TKind | TKind[], ): node is NestedTypeNode> { if (!isNode(node, TYPE_NODES)) return false; const kinds = Array.isArray(kind) ? kind : [kind]; const resolved = resolveNestedTypeNode(node); return !!node && kinds.includes(resolved.kind as TKind); } export function assertIsNestedTypeNode( node: Node | null | undefined, kind: TKind | TKind[], ): asserts node is NestedTypeNode> { const kinds = Array.isArray(kind) ? kind : [kind]; if (!isNestedTypeNode(node, kinds)) { throw new CodamaError(CODAMA_ERROR__UNEXPECTED_NESTED_NODE_KIND, { expectedKinds: kinds, kind: node?.kind ?? null, node, }); } } ================================================ FILE: packages/nodes/src/typeNodes/NumberTypeNode.ts ================================================ import type { NumberFormat, NumberTypeNode } from '@codama/node-types'; export function numberTypeNode( format: TFormat, endian: 'be' | 'le' = 'le', ): NumberTypeNode { return Object.freeze({ kind: 'numberTypeNode', // Data. format, endian, }); } export function isSignedInteger(node: NumberTypeNode): boolean { return node.format.startsWith('i'); } export function isUnsignedInteger(node: NumberTypeNode): boolean { return node.format.startsWith('u') || node.format === 'shortU16'; } export function isInteger(node: NumberTypeNode): boolean { return !node.format.startsWith('f'); } export function isDecimal(node: NumberTypeNode): boolean { return node.format.startsWith('f'); } ================================================ FILE: packages/nodes/src/typeNodes/OptionTypeNode.ts ================================================ import type { NestedTypeNode, NumberTypeNode, OptionTypeNode, TypeNode } from '@codama/node-types'; import { numberTypeNode } from './NumberTypeNode'; export function optionTypeNode< TItem extends TypeNode, TPrefix extends NestedTypeNode = NumberTypeNode<'u8'>, >( item: TItem, options: { readonly fixed?: boolean; readonly prefix?: TPrefix; } = {}, ): OptionTypeNode { return Object.freeze({ kind: 'optionTypeNode', // Data. fixed: options.fixed ?? false, // Children. item, prefix: (options.prefix ?? numberTypeNode('u8')) as TPrefix, }); } ================================================ FILE: packages/nodes/src/typeNodes/PostOffsetTypeNode.ts ================================================ import type { PostOffsetTypeNode, TypeNode } from '@codama/node-types'; export function postOffsetTypeNode( type: TType, offset: number, strategy?: PostOffsetTypeNode['strategy'], ): PostOffsetTypeNode { return Object.freeze({ kind: 'postOffsetTypeNode', // Data. offset, strategy: strategy ?? 'relative', // Children. type, }); } ================================================ FILE: packages/nodes/src/typeNodes/PreOffsetTypeNode.ts ================================================ import type { PreOffsetTypeNode, TypeNode } from '@codama/node-types'; export function preOffsetTypeNode( type: TType, offset: number, strategy?: PreOffsetTypeNode['strategy'], ): PreOffsetTypeNode { return Object.freeze({ kind: 'preOffsetTypeNode', // Data. offset, strategy: strategy ?? 'relative', // Children. type, }); } ================================================ FILE: packages/nodes/src/typeNodes/PublicKeyTypeNode.ts ================================================ import type { PublicKeyTypeNode } from '@codama/node-types'; export function publicKeyTypeNode(): PublicKeyTypeNode { return Object.freeze({ kind: 'publicKeyTypeNode' }); } ================================================ FILE: packages/nodes/src/typeNodes/RemainderOptionTypeNode.ts ================================================ import type { RemainderOptionTypeNode, TypeNode } from '@codama/node-types'; export function remainderOptionTypeNode(item: TItem): RemainderOptionTypeNode { return Object.freeze({ kind: 'remainderOptionTypeNode', // Children. item, }); } ================================================ FILE: packages/nodes/src/typeNodes/SentinelTypeNode.ts ================================================ import type { ConstantValueNode, SentinelTypeNode, TypeNode } from '@codama/node-types'; export function sentinelTypeNode( type: TType, sentinel: TSentinel, ): SentinelTypeNode { return Object.freeze({ kind: 'sentinelTypeNode', // Children. type, sentinel, }); } ================================================ FILE: packages/nodes/src/typeNodes/SetTypeNode.ts ================================================ import type { CountNode, SetTypeNode, TypeNode } from '@codama/node-types'; export function setTypeNode( item: TItem, count: TCount, ): SetTypeNode { return Object.freeze({ kind: 'setTypeNode', // Children. item, count, }); } ================================================ FILE: packages/nodes/src/typeNodes/SizePrefixTypeNode.ts ================================================ import type { NestedTypeNode, NumberTypeNode, SizePrefixTypeNode, TypeNode } from '@codama/node-types'; export function sizePrefixTypeNode< TType extends TypeNode = TypeNode, TPrefix extends NestedTypeNode = NestedTypeNode, >(type: TType, prefix: TPrefix): SizePrefixTypeNode { return Object.freeze({ kind: 'sizePrefixTypeNode', // Children. type, prefix, }); } ================================================ FILE: packages/nodes/src/typeNodes/SolAmountTypeNode.ts ================================================ import type { NestedTypeNode, NumberTypeNode, SolAmountTypeNode } from '@codama/node-types'; export function solAmountTypeNode>( number: TNumber, ): SolAmountTypeNode { return Object.freeze({ kind: 'solAmountTypeNode', // Children. number, }); } ================================================ FILE: packages/nodes/src/typeNodes/StringTypeNode.ts ================================================ import type { BytesEncoding, StringTypeNode } from '@codama/node-types'; export function stringTypeNode(encoding: TEncoding): StringTypeNode { return Object.freeze({ kind: 'stringTypeNode', // Data. encoding, }); } ================================================ FILE: packages/nodes/src/typeNodes/StructFieldTypeNode.ts ================================================ import type { StructFieldTypeNode, TypeNode, ValueNode } from '@codama/node-types'; import { camelCase, DocsInput, parseDocs } from '../shared'; export type StructFieldTypeNodeInput< TType extends TypeNode = TypeNode, TDefaultValue extends ValueNode | undefined = ValueNode | undefined, > = Omit, 'docs' | 'kind' | 'name'> & { readonly docs?: DocsInput; readonly name: string; }; export function structFieldTypeNode( input: StructFieldTypeNodeInput, ): StructFieldTypeNode { return Object.freeze({ kind: 'structFieldTypeNode', // Data. name: camelCase(input.name), ...(input.defaultValueStrategy !== undefined && { defaultValueStrategy: input.defaultValueStrategy }), docs: parseDocs(input.docs), // Children. type: input.type, ...(input.defaultValue !== undefined && { defaultValue: input.defaultValue }), }); } ================================================ FILE: packages/nodes/src/typeNodes/StructTypeNode.ts ================================================ import type { StructFieldTypeNode, StructTypeNode } from '@codama/node-types'; export function structTypeNode( fields: TFields, ): StructTypeNode { return Object.freeze({ kind: 'structTypeNode', // Children. fields, }); } ================================================ FILE: packages/nodes/src/typeNodes/TupleTypeNode.ts ================================================ import type { TupleTypeNode, TypeNode } from '@codama/node-types'; export function tupleTypeNode(items: TItems): TupleTypeNode { return Object.freeze({ kind: 'tupleTypeNode', // Children. items, }); } ================================================ FILE: packages/nodes/src/typeNodes/TypeNode.ts ================================================ // Standalone Type Node Registration. export const STANDALONE_TYPE_NODE_KINDS = [ 'amountTypeNode' as const, 'arrayTypeNode' as const, 'booleanTypeNode' as const, 'bytesTypeNode' as const, 'dateTimeTypeNode' as const, 'enumTypeNode' as const, 'fixedSizeTypeNode' as const, 'hiddenPrefixTypeNode' as const, 'hiddenSuffixTypeNode' as const, 'mapTypeNode' as const, 'numberTypeNode' as const, 'optionTypeNode' as const, 'postOffsetTypeNode' as const, 'preOffsetTypeNode' as const, 'publicKeyTypeNode' as const, 'remainderOptionTypeNode' as const, 'sentinelTypeNode' as const, 'setTypeNode' as const, 'sizePrefixTypeNode' as const, 'solAmountTypeNode' as const, 'stringTypeNode' as const, 'structTypeNode' as const, 'tupleTypeNode' as const, 'zeroableOptionTypeNode' as const, ]; // Type Node Registration. export const REGISTERED_TYPE_NODE_KINDS = [ ...STANDALONE_TYPE_NODE_KINDS, 'structFieldTypeNode' as const, 'enumEmptyVariantTypeNode' as const, 'enumStructVariantTypeNode' as const, 'enumTupleVariantTypeNode' as const, ]; /** * Type Node Helpers. * This only includes type nodes that can be used as standalone types. * E.g. this excludes structFieldTypeNode, enumEmptyVariantTypeNode, etc. * It also includes the definedTypeLinkNode to compose types. */ export const TYPE_NODES = [...STANDALONE_TYPE_NODE_KINDS, 'definedTypeLinkNode' as const]; ================================================ FILE: packages/nodes/src/typeNodes/ZeroableOptionTypeNode.ts ================================================ import type { ConstantValueNode, TypeNode, ZeroableOptionTypeNode } from '@codama/node-types'; export function zeroableOptionTypeNode( item: TItem, zeroValue?: TZeroValue, ): ZeroableOptionTypeNode { return Object.freeze({ kind: 'zeroableOptionTypeNode', // Children. item, ...(zeroValue !== undefined && { zeroValue }), }); } ================================================ FILE: packages/nodes/src/typeNodes/index.ts ================================================ export * from './AmountTypeNode'; export * from './ArrayTypeNode'; export * from './BooleanTypeNode'; export * from './BytesTypeNode'; export * from './DateTimeTypeNode'; export * from './EnumEmptyVariantTypeNode'; export * from './EnumStructVariantTypeNode'; export * from './EnumTupleVariantTypeNode'; export * from './EnumTypeNode'; export * from './EnumVariantTypeNode'; export * from './FixedSizeTypeNode'; export * from './HiddenPrefixTypeNode'; export * from './HiddenSuffixTypeNode'; export * from './MapTypeNode'; export * from './NestedTypeNode'; export * from './NumberTypeNode'; export * from './OptionTypeNode'; export * from './PostOffsetTypeNode'; export * from './PreOffsetTypeNode'; export * from './PublicKeyTypeNode'; export * from './RemainderOptionTypeNode'; export * from './SentinelTypeNode'; export * from './SetTypeNode'; export * from './SizePrefixTypeNode'; export * from './SolAmountTypeNode'; export * from './StringTypeNode'; export * from './StructFieldTypeNode'; export * from './StructTypeNode'; export * from './TupleTypeNode'; export * from './TypeNode'; export * from './ZeroableOptionTypeNode'; ================================================ FILE: packages/nodes/src/types/global.d.ts ================================================ declare const __BROWSER__: boolean; declare const __ESM__: boolean; declare const __NODEJS__: boolean; declare const __REACTNATIVE__: boolean; declare const __TEST__: boolean; declare const __VERSION__: string; ================================================ FILE: packages/nodes/src/valueNodes/ArrayValueNode.ts ================================================ import type { ArrayValueNode, ValueNode } from '@codama/node-types'; export function arrayValueNode(items: TItems): ArrayValueNode { return Object.freeze({ kind: 'arrayValueNode', // Children. items, }); } ================================================ FILE: packages/nodes/src/valueNodes/BooleanValueNode.ts ================================================ import { BooleanValueNode } from '@codama/node-types'; export function booleanValueNode(boolean: boolean): BooleanValueNode { return Object.freeze({ kind: 'booleanValueNode', // Data. boolean, }); } ================================================ FILE: packages/nodes/src/valueNodes/BytesValueNode.ts ================================================ import type { BytesEncoding, BytesValueNode } from '@codama/node-types'; export function bytesValueNode(encoding: BytesEncoding, data: string): BytesValueNode { return Object.freeze({ kind: 'bytesValueNode', // Data. data, encoding, }); } ================================================ FILE: packages/nodes/src/valueNodes/ConstantValueNode.ts ================================================ import type { BytesEncoding, ConstantValueNode, TypeNode, ValueNode } from '@codama/node-types'; import { bytesTypeNode, stringTypeNode } from '../typeNodes'; import { bytesValueNode } from './BytesValueNode'; import { stringValueNode } from './StringValueNode'; export function constantValueNode( type: TType, value: TValue, ): ConstantValueNode { return Object.freeze({ kind: 'constantValueNode', // Children. type, value, }); } export function constantValueNodeFromString(encoding: TEncoding, string: string) { return constantValueNode(stringTypeNode(encoding), stringValueNode(string)); } export function constantValueNodeFromBytes(encoding: TEncoding, data: string) { return constantValueNode(bytesTypeNode(), bytesValueNode(encoding, data)); } ================================================ FILE: packages/nodes/src/valueNodes/EnumValueNode.ts ================================================ import type { DefinedTypeLinkNode, EnumValueNode, StructValueNode, TupleValueNode } from '@codama/node-types'; import { definedTypeLinkNode } from '../linkNodes'; import { camelCase } from '../shared'; export function enumValueNode< TEnum extends DefinedTypeLinkNode = DefinedTypeLinkNode, TValue extends StructValueNode | TupleValueNode | undefined = undefined, >(enumLink: TEnum | string, variant: string, value?: TValue): EnumValueNode { return Object.freeze({ kind: 'enumValueNode', // Data. variant: camelCase(variant), // Children. enum: (typeof enumLink === 'string' ? definedTypeLinkNode(enumLink) : enumLink) as TEnum, ...(value !== undefined && { value }), }); } ================================================ FILE: packages/nodes/src/valueNodes/MapEntryValueNode.ts ================================================ import type { MapEntryValueNode, ValueNode } from '@codama/node-types'; export function mapEntryValueNode( key: TKey, value: TValue, ): MapEntryValueNode { return Object.freeze({ kind: 'mapEntryValueNode', // Children. key, value, }); } ================================================ FILE: packages/nodes/src/valueNodes/MapValueNode.ts ================================================ import type { MapEntryValueNode, MapValueNode } from '@codama/node-types'; export function mapValueNode(entries: TEntries): MapValueNode { return Object.freeze({ kind: 'mapValueNode', // Children. entries, }); } ================================================ FILE: packages/nodes/src/valueNodes/NoneValueNode.ts ================================================ import type { NoneValueNode } from '@codama/node-types'; export function noneValueNode(): NoneValueNode { return Object.freeze({ kind: 'noneValueNode' }); } ================================================ FILE: packages/nodes/src/valueNodes/NumberValueNode.ts ================================================ import type { NumberValueNode } from '@codama/node-types'; export function numberValueNode(number: number): NumberValueNode { return Object.freeze({ kind: 'numberValueNode', // Data. number, }); } ================================================ FILE: packages/nodes/src/valueNodes/PublicKeyValueNode.ts ================================================ import type { PublicKeyValueNode } from '@codama/node-types'; import { camelCase } from '../shared'; export function publicKeyValueNode(publicKey: string, identifier?: string): PublicKeyValueNode { return Object.freeze({ kind: 'publicKeyValueNode', // Data. publicKey, ...(identifier !== undefined && { identifier: camelCase(identifier) }), }); } ================================================ FILE: packages/nodes/src/valueNodes/SetValueNode.ts ================================================ import type { SetValueNode, ValueNode } from '@codama/node-types'; export function setValueNode(items: TItems): SetValueNode { return Object.freeze({ kind: 'setValueNode', // Children. items, }); } ================================================ FILE: packages/nodes/src/valueNodes/SomeValueNode.ts ================================================ import type { SomeValueNode, ValueNode } from '@codama/node-types'; export function someValueNode(value: TValue): SomeValueNode { return Object.freeze({ kind: 'someValueNode', // Children. value, }); } ================================================ FILE: packages/nodes/src/valueNodes/StringValueNode.ts ================================================ import type { StringValueNode } from '@codama/node-types'; export function stringValueNode(string: string): StringValueNode { return Object.freeze({ kind: 'stringValueNode', // Data. string, }); } ================================================ FILE: packages/nodes/src/valueNodes/StructFieldValueNode.ts ================================================ import type { StructFieldValueNode, ValueNode } from '@codama/node-types'; import { camelCase } from '../shared'; export function structFieldValueNode( name: string, value: TValue, ): StructFieldValueNode { return Object.freeze({ kind: 'structFieldValueNode', // Data. name: camelCase(name), // Children. value, }); } ================================================ FILE: packages/nodes/src/valueNodes/StructValueNode.ts ================================================ import type { StructFieldValueNode, StructValueNode } from '@codama/node-types'; export function structValueNode( fields: TFields, ): StructValueNode { return Object.freeze({ kind: 'structValueNode', // Children. fields, }); } ================================================ FILE: packages/nodes/src/valueNodes/TupleValueNode.ts ================================================ import type { TupleValueNode, ValueNode } from '@codama/node-types'; export function tupleValueNode(items: TItems): TupleValueNode { return Object.freeze({ kind: 'tupleValueNode', // Children. items, }); } ================================================ FILE: packages/nodes/src/valueNodes/ValueNode.ts ================================================ // Standalone Value Node Registration. export const STANDALONE_VALUE_NODE_KINDS = [ 'arrayValueNode' as const, 'bytesValueNode' as const, 'booleanValueNode' as const, 'constantValueNode' as const, 'enumValueNode' as const, 'mapValueNode' as const, 'noneValueNode' as const, 'numberValueNode' as const, 'setValueNode' as const, 'someValueNode' as const, 'structValueNode' as const, 'tupleValueNode' as const, 'publicKeyValueNode' as const, 'stringValueNode' as const, ]; // Value Node Registration. export const REGISTERED_VALUE_NODE_KINDS = [ ...STANDALONE_VALUE_NODE_KINDS, 'mapEntryValueNode' as const, 'structFieldValueNode' as const, ]; // Value Node Helpers. export const VALUE_NODES = STANDALONE_VALUE_NODE_KINDS; ================================================ FILE: packages/nodes/src/valueNodes/index.ts ================================================ export * from './ArrayValueNode'; export * from './BooleanValueNode'; export * from './BytesValueNode'; export * from './ConstantValueNode'; export * from './EnumValueNode'; export * from './MapEntryValueNode'; export * from './MapValueNode'; export * from './NoneValueNode'; export * from './NumberValueNode'; export * from './PublicKeyValueNode'; export * from './SetValueNode'; export * from './SomeValueNode'; export * from './StringValueNode'; export * from './StructFieldValueNode'; export * from './StructValueNode'; export * from './TupleValueNode'; export * from './ValueNode'; ================================================ FILE: packages/nodes/test/AccountNode.test.ts ================================================ import { expect, test } from 'vitest'; import { accountNode } from '../src'; test('it returns the right node kind', () => { const node = accountNode({ name: 'foo' }); expect(node.kind).toBe('accountNode'); }); test('it returns a frozen object', () => { const node = accountNode({ name: 'foo' }); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/DefinedTypeNode.test.ts ================================================ import { expect, test } from 'vitest'; import { definedTypeNode, structTypeNode } from '../src'; test('it returns the right node kind', () => { const node = definedTypeNode({ name: 'foo', type: structTypeNode([]) }); expect(node.kind).toBe('definedTypeNode'); }); test('it returns a frozen object', () => { const node = definedTypeNode({ name: 'foo', type: structTypeNode([]) }); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/ErrorNode.test.ts ================================================ import { expect, test } from 'vitest'; import { errorNode } from '../src'; test('it returns the right node kind', () => { const node = errorNode({ name: 'foo', code: 42, message: 'error message' }); expect(node.kind).toBe('errorNode'); }); test('it returns a frozen object', () => { const node = errorNode({ name: 'foo', code: 42, message: 'error message' }); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/EventNode.test.ts ================================================ import { expect, test } from 'vitest'; import { structTypeNode } from '../src'; import { eventNode } from '../src'; test('it returns the right node kind', () => { const node = eventNode({ data: structTypeNode([]), name: 'foo' }); expect(node.kind).toBe('eventNode'); }); test('it returns a frozen object', () => { const node = eventNode({ data: structTypeNode([]), name: 'foo' }); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/InstructionAccountNode.test.ts ================================================ import { expect, test } from 'vitest'; import { instructionAccountNode } from '../src'; test('it returns the right node kind', () => { const node = instructionAccountNode({ name: 'foo', isSigner: false, isWritable: false }); expect(node.kind).toBe('instructionAccountNode'); }); test('it returns a frozen object', () => { const node = instructionAccountNode({ name: 'foo', isSigner: false, isWritable: false }); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/InstructionArgumentNode.test.ts ================================================ import { expect, test } from 'vitest'; import { instructionArgumentNode, structTypeNode } from '../src'; test('it returns the right node kind', () => { const node = instructionArgumentNode({ name: 'foo', type: structTypeNode([]) }); expect(node.kind).toBe('instructionArgumentNode'); }); test('it returns a frozen object', () => { const node = instructionArgumentNode({ name: 'foo', type: structTypeNode([]) }); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/InstructionByteDeltaNode.test.ts ================================================ import { expect, test } from 'vitest'; import { instructionByteDeltaNode, numberValueNode } from '../src'; test('it returns the right node kind', () => { const node = instructionByteDeltaNode(numberValueNode(42)); expect(node.kind).toBe('instructionByteDeltaNode'); }); test('it returns a frozen object', () => { const node = instructionByteDeltaNode(numberValueNode(42)); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/InstructionNode.test.ts ================================================ import { expect, test } from 'vitest'; import { instructionNode, instructionStatusNode } from '../src'; test('it returns the right node kind', () => { const node = instructionNode({ name: 'foo' }); expect(node.kind).toBe('instructionNode'); }); test('it returns a frozen object', () => { const node = instructionNode({ name: 'foo' }); expect(Object.isFrozen(node)).toBe(true); }); test('it defaults to no status', () => { const node = instructionNode({ name: 'foo' }); expect(node.status).toBeUndefined(); }); test('it can have a live status', () => { const statusMode = instructionStatusNode('live'); const node = instructionNode({ name: 'foo', status: statusMode }); expect(node.status).toBe(statusMode); expect(node.status?.lifecycle).toBe('live'); }); test('it can have a deprecated status with message', () => { const statusMode = instructionStatusNode('deprecated', 'Use the newFoo instruction instead.'); const node = instructionNode({ name: 'foo', status: statusMode }); expect(node.status).toBe(statusMode); expect(node.status?.lifecycle).toBe('deprecated'); expect(node.status?.message).toBe('Use the newFoo instruction instead.'); }); test('it can have an archived status with message', () => { const statusMode = instructionStatusNode('archived', 'This instruction was removed in v2.0.0.'); const node = instructionNode({ name: 'foo', status: statusMode }); expect(node.status).toBe(statusMode); expect(node.status?.lifecycle).toBe('archived'); expect(node.status?.message).toBe('This instruction was removed in v2.0.0.'); }); test('it can have a draft status with message', () => { const statusMode = instructionStatusNode('draft', 'This instruction is under development.'); const node = instructionNode({ name: 'foo', status: statusMode }); expect(node.status).toBe(statusMode); expect(node.status?.lifecycle).toBe('draft'); expect(node.status?.message).toBe('This instruction is under development.'); }); test('it can have a status without a message', () => { const statusMode = instructionStatusNode('deprecated'); const node = instructionNode({ name: 'foo', status: statusMode }); expect(node.status).toBe(statusMode); expect(node.status?.lifecycle).toBe('deprecated'); expect(node.status?.message).toBeUndefined(); }); test('it can have an empty message', () => { const statusMode = instructionStatusNode('deprecated', ''); const node = instructionNode({ name: 'foo', status: statusMode }); expect(node.status).toBe(statusMode); expect(node.status?.lifecycle).toBe('deprecated'); expect(node.status?.message).toBe(''); }); ================================================ FILE: packages/nodes/test/InstructionRemainingAccountsNode.test.ts ================================================ import { expect, test } from 'vitest'; import { argumentValueNode, instructionRemainingAccountsNode } from '../src'; test('it returns the right node kind', () => { const node = instructionRemainingAccountsNode(argumentValueNode('foo')); expect(node.kind).toBe('instructionRemainingAccountsNode'); }); test('it returns a frozen object', () => { const node = instructionRemainingAccountsNode(argumentValueNode('foo')); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/InstructionStatusNode.test.ts ================================================ import { expect, test } from 'vitest'; import { instructionStatusNode } from '../src'; test('it returns the right node kind', () => { const node = instructionStatusNode('live'); expect(node.kind).toBe('instructionStatusNode'); }); test('it returns a frozen object', () => { const node = instructionStatusNode('live'); expect(Object.isFrozen(node)).toBe(true); }); test('it can have a status with message', () => { const node = instructionStatusNode('deprecated', 'Use newInstruction'); expect(node.lifecycle).toBe('deprecated'); expect(node.message).toBe('Use newInstruction'); }); test('it can have a status without message', () => { const node = instructionStatusNode('archived'); expect(node.lifecycle).toBe('archived'); expect(node.message).toBeUndefined(); }); ================================================ FILE: packages/nodes/test/Node.test.ts ================================================ import { describe, expect, test } from 'vitest'; import { assertIsNode, assertIsNodeFilter, isNode, isNodeFilter, numberTypeNode, publicKeyTypeNode, removeNullAndAssertIsNodeFilter, tupleTypeNode, } from '../src'; describe('isNode', () => { test('it checks if a given node is of the given kind', () => { expect(isNode(tupleTypeNode([]), 'tupleTypeNode')).toBe(true); expect(isNode(publicKeyTypeNode(), 'tupleTypeNode')).toBe(false); expect(isNode(null, 'tupleTypeNode')).toBe(false); }); test('it checks if a given node is part of the given kinds', () => { expect(isNode(tupleTypeNode([]), ['tupleTypeNode', 'publicKeyTypeNode'])).toBe(true); expect(isNode(publicKeyTypeNode(), ['tupleTypeNode', 'publicKeyTypeNode'])).toBe(true); expect(isNode(numberTypeNode('u8'), ['tupleTypeNode', 'publicKeyTypeNode'])).toBe(false); expect(isNode(null, ['tupleTypeNode', 'publicKeyTypeNode'])).toBe(false); }); }); describe('assertIsNode', () => { test('it asserts that a given node is of the given kind', () => { expect(() => assertIsNode(tupleTypeNode([]), 'tupleTypeNode')).not.toThrow(); expect(() => assertIsNode(publicKeyTypeNode(), 'tupleTypeNode')).toThrowError( 'Expected node of kind [tupleTypeNode], got [publicKeyTypeNode].', ); expect(() => assertIsNode(null, 'tupleTypeNode')).toThrowError( 'Expected node of kind [tupleTypeNode], got [null].', ); }); test('it asserts that a given node is part of the given kinds', () => { expect(() => assertIsNode(tupleTypeNode([]), ['tupleTypeNode', 'publicKeyTypeNode'])).not.toThrow(); expect(() => assertIsNode(publicKeyTypeNode(), ['tupleTypeNode', 'publicKeyTypeNode'])).not.toThrow(); expect(() => assertIsNode(numberTypeNode('u8'), ['tupleTypeNode', 'publicKeyTypeNode'])).toThrowError( 'Expected node of kind [tupleTypeNode,publicKeyTypeNode], got [numberTypeNode].', ); expect(() => assertIsNode(null, ['tupleTypeNode', 'publicKeyTypeNode'])).toThrowError( 'Expected node of kind [tupleTypeNode,publicKeyTypeNode], got [null].', ); }); }); describe('isNodeFilter', () => { test('it returns a callback that checks the node is of the given kind', () => { const filter = isNodeFilter('tupleTypeNode'); expect(filter(tupleTypeNode([]))).toBe(true); expect(filter(publicKeyTypeNode())).toBe(false); expect(filter(null)).toBe(false); }); test('it returns a callback that checks the node is part of the given kinds', () => { const filter = isNodeFilter(['tupleTypeNode', 'publicKeyTypeNode']); expect(filter(tupleTypeNode([]))).toBe(true); expect(filter(publicKeyTypeNode())).toBe(true); expect(filter(numberTypeNode('u8'))).toBe(false); expect(filter(null)).toBe(false); }); }); describe('assertIsNodeFilter', () => { test('it returns a callback that asserts the node is of the given kind', () => { const filter = assertIsNodeFilter('tupleTypeNode'); expect(() => filter(tupleTypeNode([]))).not.toThrow(); expect(() => filter(publicKeyTypeNode())).toThrowError( 'Expected node of kind [tupleTypeNode], got [publicKeyTypeNode].', ); expect(() => filter(null)).toThrowError('Expected node of kind [tupleTypeNode], got [null].'); }); test('it returns a callback that asserts the node is part of the given kinds', () => { const filter = assertIsNodeFilter(['tupleTypeNode', 'publicKeyTypeNode']); expect(() => filter(tupleTypeNode([]))).not.toThrow(); expect(() => filter(publicKeyTypeNode())).not.toThrow(); expect(() => filter(numberTypeNode('u8'))).toThrowError( 'Expected node of kind [tupleTypeNode,publicKeyTypeNode], got [numberTypeNode].', ); expect(() => filter(null)).toThrowError('Expected node of kind [tupleTypeNode,publicKeyTypeNode], got [null].'); }); }); describe('removeNullAndAssertIsNodeFilter', () => { test('it returns a callback that filters out null values and asserts the node is of the given kind', () => { const filter = removeNullAndAssertIsNodeFilter('tupleTypeNode'); expect([tupleTypeNode([]), null].filter(filter)).toEqual([tupleTypeNode([])]); expect(() => [tupleTypeNode([]), publicKeyTypeNode(), null].filter(filter)).toThrowError( 'Expected node of kind [tupleTypeNode], got [publicKeyTypeNode].', ); }); test('it returns a callback that filters out null values and asserts the node is part of the given kinds', () => { const filter = removeNullAndAssertIsNodeFilter(['tupleTypeNode', 'publicKeyTypeNode']); expect([tupleTypeNode([]), publicKeyTypeNode(), null].filter(filter)).toEqual([ tupleTypeNode([]), publicKeyTypeNode(), ]); expect(() => [tupleTypeNode([]), numberTypeNode('u8'), null].filter(filter)).toThrowError( 'Expected node of kind [tupleTypeNode,publicKeyTypeNode], got [numberTypeNode].', ); }); }); ================================================ FILE: packages/nodes/test/Node.typetest.ts ================================================ import type { Node, PublicKeyTypeNode, TupleTypeNode } from '@codama/node-types'; import { assertIsNode, assertIsNodeFilter, isNode, isNodeFilter, REGISTERED_NODE_KINDS, removeNullAndAssertIsNodeFilter, } from '../src'; // [DESCRIBE] Registered node kinds. { // It matches exactly with Node['kind']. { REGISTERED_NODE_KINDS satisfies readonly Node['kind'][]; null as unknown as Node['kind'] satisfies (typeof REGISTERED_NODE_KINDS)[number]; } } // [DESCRIBE] isNode. { // It narrows the type of a node to the given kind. { const node = {} as Node | null; if (isNode(node, 'tupleTypeNode')) { node satisfies TupleTypeNode; // @ts-expect-error Expected TupleTypeNode. node satisfies PublicKeyTypeNode; } } // It narrows the type of a node to union of the given kinds. { const node = {} as Node | null; if (isNode(node, ['tupleTypeNode', 'publicKeyTypeNode'])) { node satisfies PublicKeyTypeNode | TupleTypeNode; // @ts-expect-error Expected PublicKeyTypeNode | TupleTypeNode. node satisfies TupleTypeNode; // @ts-expect-error Expected PublicKeyTypeNode | TupleTypeNode. node satisfies PublicKeyTypeNode; } } } // [DESCRIBE] assertIsNode. { // It narrows the type of a node to the given kind. { const node = {} as Node | null; assertIsNode(node, 'tupleTypeNode'); node satisfies TupleTypeNode; // @ts-expect-error Expected TupleTypeNode. node satisfies PublicKeyTypeNode; } // It narrows the type of a node to union of the given kinds. { const node = {} as Node | null; assertIsNode(node, ['tupleTypeNode', 'publicKeyTypeNode']); node satisfies PublicKeyTypeNode | TupleTypeNode; // @ts-expect-error Expected PublicKeyTypeNode | TupleTypeNode. node satisfies TupleTypeNode; // @ts-expect-error Expected PublicKeyTypeNode | TupleTypeNode. node satisfies PublicKeyTypeNode; } } // [DESCRIBE] isNodeFilter. { // It narrows the type of an array of nodes to the given kind. { const nodes = ([] as (Node | null)[]).filter(isNodeFilter('tupleTypeNode')); nodes satisfies TupleTypeNode[]; // @ts-expect-error Expected TupleTypeNode. nodes satisfies PublicKeyTypeNode[]; } // It narrows the type of an array of nodes to union of the given kinds. { const nodes = ([] as (Node | null)[]).filter(isNodeFilter(['tupleTypeNode', 'publicKeyTypeNode'])); nodes satisfies (PublicKeyTypeNode | TupleTypeNode)[]; // @ts-expect-error Expected PublicKeyTypeNode | TupleTypeNode. nodes satisfies TupleTypeNode[]; // @ts-expect-error Expected PublicKeyTypeNode | TupleTypeNode. nodes satisfies PublicKeyTypeNode[]; } } // [DESCRIBE] assertIsNodeFilter. { // It narrows the type of an array of nodes to the given kind. { const nodes = ([] as (Node | null)[]).filter(assertIsNodeFilter('tupleTypeNode')); nodes satisfies TupleTypeNode[]; // @ts-expect-error Expected TupleTypeNode. nodes satisfies PublicKeyTypeNode[]; } // It narrows the type of an array of nodes to union of the given kinds. { const nodes = ([] as (Node | null)[]).filter(assertIsNodeFilter(['tupleTypeNode', 'publicKeyTypeNode'])); nodes satisfies (PublicKeyTypeNode | TupleTypeNode)[]; // @ts-expect-error Expected PublicKeyTypeNode | TupleTypeNode. nodes satisfies TupleTypeNode[]; // @ts-expect-error Expected PublicKeyTypeNode | TupleTypeNode. nodes satisfies PublicKeyTypeNode[]; } } // [DESCRIBE] removeNullAndAssertIsNodeFilter. { // It narrows the type of an array of nodes to the given kind. { const nodes = ([] as (Node | null)[]).filter(removeNullAndAssertIsNodeFilter('tupleTypeNode')); nodes satisfies TupleTypeNode[]; // @ts-expect-error Expected TupleTypeNode[] nodes satisfies PublicKeyTypeNode[]; } // It narrows the type of an array of nodes to union of the given kinds. { const nodes = ([] as (Node | null)[]).filter( removeNullAndAssertIsNodeFilter(['tupleTypeNode', 'publicKeyTypeNode']), ); nodes satisfies (PublicKeyTypeNode | TupleTypeNode)[]; // @ts-expect-error Expected (PublicKeyTypeNode | TupleTypeNode)[] nodes satisfies TupleTypeNode[]; // @ts-expect-error Expected (PublicKeyTypeNode | TupleTypeNode)[] nodes satisfies PublicKeyTypeNode[]; } } ================================================ FILE: packages/nodes/test/PdaNode.test.ts ================================================ import { expect, test } from 'vitest'; import { pdaNode } from '../src'; test('it returns the right node kind', () => { const node = pdaNode({ name: 'foo', seeds: [] }); expect(node.kind).toBe('pdaNode'); }); test('it returns a frozen object', () => { const node = pdaNode({ name: 'foo', seeds: [] }); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/ProgramNode.test.ts ================================================ import { expect, test } from 'vitest'; import { programNode } from '../src'; test('it returns the right node kind', () => { const node = programNode({ name: 'foo', publicKey: '1111' }); expect(node.kind).toBe('programNode'); }); test('it returns a frozen object', () => { const node = programNode({ name: 'foo', publicKey: '1111' }); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/RootNode.test.ts ================================================ import type { CodamaVersion } from '@codama/node-types'; import { expect, expectTypeOf, test } from 'vitest'; import { programNode, rootNode } from '../src'; test('it returns the right node kind', () => { const root = rootNode(programNode({ name: 'foo', publicKey: '1111' })); expect(root.kind).toBe('rootNode'); }); test('it returns the right Codama standard', () => { const root = rootNode(programNode({ name: 'foo', publicKey: '1111' })); expect(root.standard).toBe('codama'); }); test('it returns the right Codama version', () => { const root = rootNode(programNode({ name: 'foo', publicKey: '1111' })); expect(root.version).toBe(__VERSION__); expectTypeOf(root.version).toMatchTypeOf(); }); test('it returns a frozen object', () => { const root = rootNode(programNode({ name: 'foo', publicKey: '1111' })); expect(Object.isFrozen(root)).toBe(true); }); ================================================ FILE: packages/nodes/test/contextualValueNodes/AccountBumpValueNode.test.ts ================================================ import { expect, test } from 'vitest'; import { accountBumpValueNode } from '../../src'; test('it returns the right node kind', () => { const node = accountBumpValueNode('associatedToken'); expect(node.kind).toBe('accountBumpValueNode'); }); test('it returns a frozen object', () => { const node = accountBumpValueNode('associatedToken'); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/contextualValueNodes/AccountValueNode.test.ts ================================================ import { expect, test } from 'vitest'; import { accountValueNode } from '../../src'; test('it returns the right node kind', () => { const node = accountValueNode('mint'); expect(node.kind).toBe('accountValueNode'); }); test('it returns a frozen object', () => { const node = accountValueNode('mint'); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/contextualValueNodes/ArgumentValueNode.test.ts ================================================ import { expect, test } from 'vitest'; import { argumentValueNode } from '../../src'; test('it returns the right node kind', () => { const node = argumentValueNode('space'); expect(node.kind).toBe('argumentValueNode'); }); test('it returns a frozen object', () => { const node = argumentValueNode('space'); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/contextualValueNodes/ConditionalValueNode.test.ts ================================================ import { expect, test } from 'vitest'; import { accountValueNode, argumentValueNode, conditionalValueNode } from '../../src'; test('it returns the right node kind', () => { const node = conditionalValueNode({ condition: accountValueNode('token'), ifTrue: argumentValueNode('space') }); expect(node.kind).toBe('conditionalValueNode'); }); test('it returns a frozen object', () => { const node = conditionalValueNode({ condition: accountValueNode('token'), ifTrue: argumentValueNode('space') }); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/contextualValueNodes/ContextualValueNode.typetest.ts ================================================ import type { RegisteredContextualValueNode } from '@codama/node-types'; import { REGISTERED_CONTEXTUAL_VALUE_NODE_KINDS } from '../../src'; // [DESCRIBE] Registered contextual value node kinds. { // It matches exactly with RegisteredContextualValueNode['kind']. { REGISTERED_CONTEXTUAL_VALUE_NODE_KINDS satisfies readonly RegisteredContextualValueNode['kind'][]; null as unknown as RegisteredContextualValueNode['kind'] satisfies (typeof REGISTERED_CONTEXTUAL_VALUE_NODE_KINDS)[number]; } } ================================================ FILE: packages/nodes/test/contextualValueNodes/IdentityValueNode.test.ts ================================================ import { expect, test } from 'vitest'; import { identityValueNode } from '../../src'; test('it returns the right node kind', () => { const node = identityValueNode(); expect(node.kind).toBe('identityValueNode'); }); test('it returns a frozen object', () => { const node = identityValueNode(); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/contextualValueNodes/PayerValueNode.test.ts ================================================ import { expect, test } from 'vitest'; import { payerValueNode } from '../../src'; test('it returns the right node kind', () => { const node = payerValueNode(); expect(node.kind).toBe('payerValueNode'); }); test('it returns a frozen object', () => { const node = payerValueNode(); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/contextualValueNodes/PdaSeedValueNode.test.ts ================================================ import { expect, test } from 'vitest'; import { accountValueNode, pdaSeedValueNode } from '../../src'; test('it returns the right node kind', () => { const node = pdaSeedValueNode('token', accountValueNode('token')); expect(node.kind).toBe('pdaSeedValueNode'); }); test('it returns a frozen object', () => { const node = pdaSeedValueNode('token', accountValueNode('token')); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/contextualValueNodes/PdaValueNode.test.ts ================================================ import { expect, test } from 'vitest'; import { pdaValueNode } from '../../src'; test('it returns the right node kind', () => { const node = pdaValueNode('associatedToken', []); expect(node.kind).toBe('pdaValueNode'); }); test('it returns a frozen object', () => { const node = pdaValueNode('associatedToken', []); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/contextualValueNodes/ProgramIdValueNode.test.ts ================================================ import { expect, test } from 'vitest'; import { programIdValueNode } from '../../src'; test('it returns the right node kind', () => { const node = programIdValueNode(); expect(node.kind).toBe('programIdValueNode'); }); test('it returns a frozen object', () => { const node = programIdValueNode(); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/contextualValueNodes/ResolverValueNode.test.ts ================================================ import { expect, test } from 'vitest'; import { resolverValueNode } from '../../src'; test('it returns the right node kind', () => { const node = resolverValueNode('foo'); expect(node.kind).toBe('resolverValueNode'); }); test('it returns a frozen object', () => { const node = resolverValueNode('foo'); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/countNodes/CountNode.typetest.ts ================================================ import type { RegisteredCountNode } from '@codama/node-types'; import { REGISTERED_COUNT_NODE_KINDS } from '../../src'; // [DESCRIBE] Registered count node kinds. { // It matches exactly with RegisteredCountNode['kind']. { REGISTERED_COUNT_NODE_KINDS satisfies readonly RegisteredCountNode['kind'][]; null as unknown as RegisteredCountNode['kind'] satisfies (typeof REGISTERED_COUNT_NODE_KINDS)[number]; } } ================================================ FILE: packages/nodes/test/countNodes/FixedCountNode.test.ts ================================================ import { expect, test } from 'vitest'; import { fixedCountNode } from '../../src'; test('it returns the right node kind', () => { const node = fixedCountNode(42); expect(node.kind).toBe('fixedCountNode'); }); test('it returns a frozen object', () => { const node = fixedCountNode(42); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/countNodes/PrefixedCountNode.test.ts ================================================ import { expect, test } from 'vitest'; import { numberTypeNode, prefixedCountNode } from '../../src'; test('it returns the right node kind', () => { const node = prefixedCountNode(numberTypeNode('u32')); expect(node.kind).toBe('prefixedCountNode'); }); test('it returns a frozen object', () => { const node = prefixedCountNode(numberTypeNode('u32')); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/countNodes/RemainderCountNode.test.ts ================================================ import { expect, test } from 'vitest'; import { remainderCountNode } from '../../src'; test('it returns the right node kind', () => { const node = remainderCountNode(); expect(node.kind).toBe('remainderCountNode'); }); test('it returns a frozen object', () => { const node = remainderCountNode(); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/discriminatorNodes/ConstantDiscriminatorNode.test.ts ================================================ import { expect, test } from 'vitest'; import { constantDiscriminatorNode, constantValueNodeFromBytes } from '../../src'; test('it returns the right node kind', () => { const node = constantDiscriminatorNode(constantValueNodeFromBytes('base16', 'aabbccdd')); expect(node.kind).toBe('constantDiscriminatorNode'); }); test('it returns a frozen object', () => { const node = constantDiscriminatorNode(constantValueNodeFromBytes('base16', 'aabbccdd')); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/discriminatorNodes/DiscriminatorNode.typetest.ts ================================================ import type { RegisteredDiscriminatorNode } from '@codama/node-types'; import { REGISTERED_DISCRIMINATOR_NODE_KINDS } from '../../src'; // [DESCRIBE] Registered discriminator node kinds. { // It matches exactly with RegisteredDiscriminatorNode['kind']. { REGISTERED_DISCRIMINATOR_NODE_KINDS satisfies readonly RegisteredDiscriminatorNode['kind'][]; null as unknown as RegisteredDiscriminatorNode['kind'] satisfies (typeof REGISTERED_DISCRIMINATOR_NODE_KINDS)[number]; } } ================================================ FILE: packages/nodes/test/discriminatorNodes/FieldDiscriminatorNode.test.ts ================================================ import { expect, test } from 'vitest'; import { fieldDiscriminatorNode } from '../../src'; test('it returns the right node kind', () => { const node = fieldDiscriminatorNode('discriminator'); expect(node.kind).toBe('fieldDiscriminatorNode'); }); test('it returns a frozen object', () => { const node = fieldDiscriminatorNode('discriminator'); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/discriminatorNodes/SizeDiscriminatorNode.test.ts ================================================ import { expect, test } from 'vitest'; import { sizeDiscriminatorNode } from '../../src'; test('it returns the right node kind', () => { const node = sizeDiscriminatorNode(42); expect(node.kind).toBe('sizeDiscriminatorNode'); }); test('it returns a frozen object', () => { const node = sizeDiscriminatorNode(42); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/linkNodes/AccountLinkNode.test.ts ================================================ import { expect, test } from 'vitest'; import { accountLinkNode } from '../../src'; test('it returns the right node kind', () => { const node = accountLinkNode('token'); expect(node.kind).toBe('accountLinkNode'); }); test('it returns a frozen object', () => { const node = accountLinkNode('token'); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/linkNodes/DefinedTypeLinkNode.test.ts ================================================ import { expect, test } from 'vitest'; import { definedTypeLinkNode } from '../../src'; test('it returns the right node kind', () => { const node = definedTypeLinkNode('config'); expect(node.kind).toBe('definedTypeLinkNode'); }); test('it returns a frozen object', () => { const node = definedTypeLinkNode('config'); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/linkNodes/InstructionAccountLinkNode.test.ts ================================================ import { expect, test } from 'vitest'; import { instructionAccountLinkNode } from '../../src'; test('it returns the right node kind', () => { const node = instructionAccountLinkNode('mint'); expect(node.kind).toBe('instructionAccountLinkNode'); }); test('it returns a frozen object', () => { const node = instructionAccountLinkNode('mint'); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/linkNodes/InstructionArgumentLinkNode.test.ts ================================================ import { expect, test } from 'vitest'; import { instructionArgumentLinkNode } from '../../src'; test('it returns the right node kind', () => { const node = instructionArgumentLinkNode('amount'); expect(node.kind).toBe('instructionArgumentLinkNode'); }); test('it returns a frozen object', () => { const node = instructionArgumentLinkNode('amount'); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/linkNodes/InstructionLinkNode.test.ts ================================================ import { expect, test } from 'vitest'; import { instructionLinkNode } from '../../src'; test('it returns the right node kind', () => { const node = instructionLinkNode('transferTokens'); expect(node.kind).toBe('instructionLinkNode'); }); test('it returns a frozen object', () => { const node = instructionLinkNode('transferTokens'); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/linkNodes/LinkNode.typetest.ts ================================================ import type { RegisteredLinkNode } from '@codama/node-types'; import { REGISTERED_LINK_NODE_KINDS } from '../../src'; // [DESCRIBE] Registered link node kinds. { // It matches exactly with RegisteredLinkNode['kind']. { REGISTERED_LINK_NODE_KINDS satisfies readonly RegisteredLinkNode['kind'][]; null as unknown as RegisteredLinkNode['kind'] satisfies (typeof REGISTERED_LINK_NODE_KINDS)[number]; } } ================================================ FILE: packages/nodes/test/linkNodes/PdaLinkNode.test.ts ================================================ import { expect, test } from 'vitest'; import { pdaLinkNode } from '../../src'; test('it returns the right node kind', () => { const node = pdaLinkNode('associatedToken'); expect(node.kind).toBe('pdaLinkNode'); }); test('it returns a frozen object', () => { const node = pdaLinkNode('associatedToken'); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/linkNodes/ProgramLinkNode.test.ts ================================================ import { expect, test } from 'vitest'; import { programLinkNode } from '../../src'; test('it returns the right node kind', () => { const node = programLinkNode('system'); expect(node.kind).toBe('programLinkNode'); }); test('it returns a frozen object', () => { const node = programLinkNode('system'); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/pdaSeedNodes/ConstantPdaSeedNode.test.ts ================================================ import { expect, test } from 'vitest'; import { constantPdaSeedNode, numberTypeNode, numberValueNode } from '../../src'; test('it returns the right node kind', () => { const node = constantPdaSeedNode(numberTypeNode('u64'), numberValueNode(42)); expect(node.kind).toBe('constantPdaSeedNode'); }); test('it returns a frozen object', () => { const node = constantPdaSeedNode(numberTypeNode('u64'), numberValueNode(42)); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/pdaSeedNodes/PdaSeedNode.typetest.ts ================================================ import type { RegisteredPdaSeedNode } from '@codama/node-types'; import { REGISTERED_PDA_SEED_NODE_KINDS } from '../../src'; // [DESCRIBE] Registered pda seed node kinds. { // It matches exactly with RegisteredPdaSeedNode['kind']. { REGISTERED_PDA_SEED_NODE_KINDS satisfies readonly RegisteredPdaSeedNode['kind'][]; null as unknown as RegisteredPdaSeedNode['kind'] satisfies (typeof REGISTERED_PDA_SEED_NODE_KINDS)[number]; } } ================================================ FILE: packages/nodes/test/pdaSeedNodes/VariablePdaSeedNode.test.ts ================================================ import { expect, test } from 'vitest'; import { numberTypeNode, variablePdaSeedNode } from '../../src'; test('it returns the right node kind', () => { const node = variablePdaSeedNode('edition', numberTypeNode('u64')); expect(node.kind).toBe('variablePdaSeedNode'); }); test('it returns a frozen object', () => { const node = variablePdaSeedNode('edition', numberTypeNode('u64')); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/shared/stringCases.test.ts ================================================ import { describe, expect, test } from 'vitest'; import { camelCase, snakeCase, titleCase } from '../../src'; describe('snakeCase', () => { test('casing', () => { expect(snakeCase('lowercased')).toBe('lowercased'); expect(snakeCase('UPPERCASED')).toBe('u_p_p_e_r_c_a_s_e_d'); expect(snakeCase('Capitalized')).toBe('capitalized'); }); test('numbers', () => { expect(snakeCase('1before after2 bet3ween')).toBe('1before_after2_bet3ween'); expect(snakeCase('50m3 1 2 3 numb3rs 8 3v3rywh3r3 9')).toBe('50m3_1_2_3_numb3rs_8_3v3rywh3r3_9'); expect(snakeCase(snakeCase('50m3 1 2 3 numb3rs 8 3v3rywh3r3 9'))).toBe('50m3_1_2_3_numb3rs_8_3v3rywh3r3_9'); }); test('special characters', () => { expect(snakeCase('some::special\\\\chars+++in=between')).toBe('some_special_chars_in_between'); expect(snakeCase('$peçia!::ch*rs')).toBe('pe_ia_ch_rs'); expect(snakeCase('multiple.........dots')).toBe('multiple_dots'); expect(snakeCase('multiple---------dashes')).toBe('multiple_dashes'); expect(snakeCase('multiple_________underscores')).toBe('multiple_underscores'); }); test('from snake case', () => { expect(snakeCase('from_lowercased_snake_case')).toBe('from_lowercased_snake_case'); expect(snakeCase('From_Capitalized_Snake_Case')).toBe('from_capitalized_snake_case'); expect(snakeCase('FROM_UPPERCASED_SNAKE_CASE')).toBe('f_r_o_m_u_p_p_e_r_c_a_s_e_d_s_n_a_k_e_c_a_s_e'); expect(snakeCase('fr0m_5nak3_c4s3_w1th_42n_numb3r5')).toBe('fr0m_5nak3_c4s3_w1th_42n_numb3r5'); expect(snakeCase('frøm_snake_case_w:th_$peçia!_ch*rs')).toBe('fr_m_snake_case_w_th_pe_ia_ch_rs'); expect(snakeCase(snakeCase('frøm_d0ubl3_Snake_c*se'))).toBe('fr_m_d0ubl3_snake_c_se'); }); test('from title case', () => { expect(snakeCase('from lowercased title case')).toBe('from_lowercased_title_case'); expect(snakeCase('From Capitalized Title Case')).toBe('from_capitalized_title_case'); expect(snakeCase('FROM UPPERCASED TITLE CASE')).toBe('f_r_o_m_u_p_p_e_r_c_a_s_e_d_t_i_t_l_e_c_a_s_e'); expect(snakeCase('Fr0m T1tl3 C4s3 W1th 42n Numb3r5')).toBe('fr0m_t1tl3_c4s3_w1th_42n_numb3r5'); expect(snakeCase('Frøm Title Case W:th $peçia! Ch*rs')).toBe('fr_m_title_case_w_th_pe_ia_ch_rs'); expect(snakeCase(snakeCase('Frøm D0ubl3 Title C*se'))).toBe('fr_m_d0ubl3_title_c_se'); }); test('from pascal case', () => { expect(snakeCase('FromPascaleCase')).toBe('from_pascale_case'); expect(snakeCase('Fr0mP45c4l3C4s3W1th42nNumb3r5')).toBe('fr0m_p45c4l3_c4s3_w1th42n_numb3r5'); expect(snakeCase('FrømPascaleCaseW:th$peçia!Ch*rs')).toBe('fr_m_pascale_case_w_th_pe_ia_ch_rs'); expect(snakeCase(snakeCase('FrømD0ubl3PascaleC*se'))).toBe('fr_m_d0ubl3_pascale_c_se'); }); test('from camel case', () => { expect(snakeCase('FromCamelCase')).toBe('from_camel_case'); expect(snakeCase('Fr0mC4m3lC4s3W1th42nNumb3r5')).toBe('fr0m_c4m3l_c4s3_w1th42n_numb3r5'); expect(snakeCase('FrømCamelCaseW:th$peçia!Ch*rs')).toBe('fr_m_camel_case_w_th_pe_ia_ch_rs'); expect(snakeCase(snakeCase('FrømD0ubl3CamelC*se'))).toBe('fr_m_d0ubl3_camel_c_se'); }); test('from paths', () => { expect(snakeCase('crate::my_module::my_type')).toBe('crate_my_module_my_type'); expect(snakeCase('/Users/username/My File.txt')).toBe('users_username_my_file_txt'); expect(snakeCase('C:\\Users\\username\\My\\ File.txt')).toBe('c_users_username_my_file_txt'); }); }); describe('titleCase', () => { test('casing', () => { expect(titleCase('lowercased')).toBe('Lowercased'); expect(titleCase('UPPERCASED')).toBe('U P P E R C A S E D'); expect(titleCase('Capitalized')).toBe('Capitalized'); }); test('numbers', () => { expect(titleCase('1before after2 bet3ween')).toBe('1before After2 Bet3ween'); expect(titleCase('50m3 1 2 3 numb3rs 8 3v3rywh3r3 9')).toBe('50m3 1 2 3 Numb3rs 8 3v3rywh3r3 9'); expect(titleCase(titleCase('50m3 1 2 3 numb3rs 8 3v3rywh3r3 9'))).toBe('50m3 1 2 3 Numb3rs 8 3v3rywh3r3 9'); }); test('special characters', () => { expect(titleCase('some::special\\\\chars+++in=between')).toBe('Some Special Chars In Between'); expect(titleCase('$peçia!::ch*rs')).toBe('Pe Ia Ch Rs'); expect(titleCase('multiple.........dots')).toBe('Multiple Dots'); expect(titleCase('multiple---------dashes')).toBe('Multiple Dashes'); expect(titleCase('multiple_________underscores')).toBe('Multiple Underscores'); }); test('from snake case', () => { expect(titleCase('from_lowercased_snake_case')).toBe('From Lowercased Snake Case'); expect(titleCase('From_Capitalized_Snake_Case')).toBe('From Capitalized Snake Case'); expect(titleCase('FROM_UPPERCASED_SNAKE_CASE')).toBe('F R O M U P P E R C A S E D S N A K E C A S E'); expect(titleCase('fr0m_5nak3_c4s3_w1th_42n_numb3r5')).toBe('Fr0m 5nak3 C4s3 W1th 42n Numb3r5'); expect(titleCase('frøm_snake_case_w:th_$peçia!_ch*rs')).toBe('Fr M Snake Case W Th Pe Ia Ch Rs'); expect(titleCase(titleCase('frøm_d0ubl3_Snake_c*se'))).toBe('Fr M D0ubl3 Snake C Se'); }); test('from title case', () => { expect(titleCase('from lowercased title case')).toBe('From Lowercased Title Case'); expect(titleCase('From Capitalized Title Case')).toBe('From Capitalized Title Case'); expect(titleCase('FROM UPPERCASED TITLE CASE')).toBe('F R O M U P P E R C A S E D T I T L E C A S E'); expect(titleCase('Fr0m T1tl3 C4s3 W1th 42n Numb3r5')).toBe('Fr0m T1tl3 C4s3 W1th 42n Numb3r5'); expect(titleCase('Frøm Title Case W:th $peçia! Ch*rs')).toBe('Fr M Title Case W Th Pe Ia Ch Rs'); expect(titleCase(titleCase('Frøm D0ubl3 Title C*se'))).toBe('Fr M D0ubl3 Title C Se'); }); test('from pascal case', () => { expect(titleCase('FromPascaleCase')).toBe('From Pascale Case'); expect(titleCase('Fr0mP45c4l3C4s3W1th42nNumb3r5')).toBe('Fr0m P45c4l3 C4s3 W1th42n Numb3r5'); expect(titleCase('FrømPascaleCaseW:th$peçia!Ch*rs')).toBe('Fr M Pascale Case W Th Pe Ia Ch Rs'); expect(titleCase(titleCase('FrømD0ubl3PascaleC*se'))).toBe('Fr M D0ubl3 Pascale C Se'); }); test('from camel case', () => { expect(titleCase('FromCamelCase')).toBe('From Camel Case'); expect(titleCase('Fr0mC4m3lC4s3W1th42nNumb3r5')).toBe('Fr0m C4m3l C4s3 W1th42n Numb3r5'); expect(titleCase('FrømCamelCaseW:th$peçia!Ch*rs')).toBe('Fr M Camel Case W Th Pe Ia Ch Rs'); expect(titleCase(titleCase('FrømD0ubl3CamelC*se'))).toBe('Fr M D0ubl3 Camel C Se'); }); test('from paths', () => { expect(titleCase('crate::my_module::my_type')).toBe('Crate My Module My Type'); expect(titleCase('/Users/username/My File.txt')).toBe('Users Username My File Txt'); expect(titleCase('C:\\Users\\username\\My\\ File.txt')).toBe('C Users Username My File Txt'); }); }); describe('camelCase', () => { test('casing', () => { expect(camelCase('lowercased')).toBe('lowercased'); expect(camelCase('UPPERCASED')).toBe('uPPERCASED'); expect(camelCase('Capitalized')).toBe('capitalized'); }); test('numbers', () => { expect(camelCase('1before after2 bet3ween')).toBe('1beforeAfter2Bet3ween'); expect(camelCase('50m3 1 2 3 numb3rs 8 3v3rywh3r3 9')).toBe('50m3123Numb3rs83v3rywh3r39'); expect(titleCase(camelCase('50m3 1 2 3 numb3rs 8 3v3rywh3r3 9'))).toBe('50m3123 Numb3rs83v3rywh3r39'); }); test('special characters', () => { expect(camelCase('some::special\\\\chars+++in=between')).toBe('someSpecialCharsInBetween'); expect(camelCase('$peçia!::ch*rs')).toBe('peIaChRs'); expect(camelCase('multiple.........dots')).toBe('multipleDots'); expect(camelCase('multiple---------dashes')).toBe('multipleDashes'); expect(camelCase('multiple_________underscores')).toBe('multipleUnderscores'); }); test('from snake case', () => { expect(camelCase('from_lowercased_snake_case')).toBe('fromLowercasedSnakeCase'); expect(camelCase('From_Capitalized_Snake_Case')).toBe('fromCapitalizedSnakeCase'); expect(camelCase('FROM_UPPERCASED_SNAKE_CASE')).toBe('fROMUPPERCASEDSNAKECASE'); expect(camelCase('fr0m_5nak3_c4s3_w1th_42n_numb3r5')).toBe('fr0m5nak3C4s3W1th42nNumb3r5'); expect(camelCase('frøm_snake_case_w:th_$peçia!_ch*rs')).toBe('frMSnakeCaseWThPeIaChRs'); expect(camelCase(camelCase('frøm_d0ubl3_Snake_c*se'))).toBe('frMD0ubl3SnakeCSe'); }); test('from title case', () => { expect(camelCase('from lowercased title case')).toBe('fromLowercasedTitleCase'); expect(camelCase('From Capitalized Title Case')).toBe('fromCapitalizedTitleCase'); expect(camelCase('FROM UPPERCASED TITLE CASE')).toBe('fROMUPPERCASEDTITLECASE'); expect(camelCase('Fr0m T1tl3 C4s3 W1th 42n Numb3r5')).toBe('fr0mT1tl3C4s3W1th42nNumb3r5'); expect(camelCase('Frøm Title Case W:th $peçia! Ch*rs')).toBe('frMTitleCaseWThPeIaChRs'); expect(camelCase(camelCase('Frøm D0ubl3 Title C*se'))).toBe('frMD0ubl3TitleCSe'); }); test('from pascal case', () => { expect(camelCase('FromPascaleCase')).toBe('fromPascaleCase'); expect(camelCase('Fr0mP45c4l3C4s3W1th42nNumb3r5')).toBe('fr0mP45c4l3C4s3W1th42nNumb3r5'); expect(camelCase('FrømPascaleCaseW:th$peçia!Ch*rs')).toBe('frMPascaleCaseWThPeIaChRs'); expect(camelCase(camelCase('FrømD0ubl3PascaleC*se'))).toBe('frMD0ubl3PascaleCSe'); }); test('from camel case', () => { expect(camelCase('FromCamelCase')).toBe('fromCamelCase'); expect(camelCase('Fr0mC4m3lC4s3W1th42nNumb3r5')).toBe('fr0mC4m3lC4s3W1th42nNumb3r5'); expect(camelCase('FrømCamelCaseW:th$peçia!Ch*rs')).toBe('frMCamelCaseWThPeIaChRs'); expect(camelCase(camelCase('FrømD0ubl3CamelC*se'))).toBe('frMD0ubl3CamelCSe'); }); test('from paths', () => { expect(camelCase('crate::my_module::my_type')).toBe('crateMyModuleMyType'); expect(camelCase('/Users/username/My File.txt')).toBe('usersUsernameMyFileTxt'); expect(camelCase('C:\\Users\\username\\My\\ File.txt')).toBe('cUsersUsernameMyFileTxt'); }); }); ================================================ FILE: packages/nodes/test/typeNodes/AmountTypeNode.test.ts ================================================ import { expect, test } from 'vitest'; import { amountTypeNode, numberTypeNode } from '../../src'; test('it returns the right node kind', () => { const node = amountTypeNode(numberTypeNode('u64'), 9); expect(node.kind).toBe('amountTypeNode'); }); test('it returns a frozen object', () => { const node = amountTypeNode(numberTypeNode('u64'), 9); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/typeNodes/ArrayTypeNode.test.ts ================================================ import { expect, test } from 'vitest'; import { arrayTypeNode, numberTypeNode, remainderCountNode } from '../../src'; test('it returns the right node kind', () => { const node = arrayTypeNode(numberTypeNode('u64'), remainderCountNode()); expect(node.kind).toBe('arrayTypeNode'); }); test('it returns a frozen object', () => { const node = arrayTypeNode(numberTypeNode('u64'), remainderCountNode()); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/typeNodes/BooleanTypeNode.test.ts ================================================ import { expect, test } from 'vitest'; import { booleanTypeNode } from '../../src'; test('it returns the right node kind', () => { const node = booleanTypeNode(); expect(node.kind).toBe('booleanTypeNode'); }); test('it returns a frozen object', () => { const node = booleanTypeNode(); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/typeNodes/BytesTypeNode.test.ts ================================================ import { expect, test } from 'vitest'; import { bytesTypeNode } from '../../src'; test('it returns the right node kind', () => { const node = bytesTypeNode(); expect(node.kind).toBe('bytesTypeNode'); }); test('it returns a frozen object', () => { const node = bytesTypeNode(); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/typeNodes/DateTimeTypeNode.test.ts ================================================ import { expect, test } from 'vitest'; import { dateTimeTypeNode, numberTypeNode } from '../../src'; test('it returns the right node kind', () => { const node = dateTimeTypeNode(numberTypeNode('u64')); expect(node.kind).toBe('dateTimeTypeNode'); }); test('it returns a frozen object', () => { const node = dateTimeTypeNode(numberTypeNode('u64')); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/typeNodes/EnumEmptyVariantTypeNode.test.ts ================================================ import { expect, test } from 'vitest'; import { enumEmptyVariantTypeNode } from '../../src'; test('it returns the right node kind', () => { const node = enumEmptyVariantTypeNode('apple'); expect(node.kind).toBe('enumEmptyVariantTypeNode'); }); test('it returns a frozen object', () => { const node = enumEmptyVariantTypeNode('apple'); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/typeNodes/EnumStructVariantTypeNode.test.ts ================================================ import { expect, test } from 'vitest'; import { enumStructVariantTypeNode, structTypeNode } from '../../src'; test('it returns the right node kind', () => { const node = enumStructVariantTypeNode('apple', structTypeNode([])); expect(node.kind).toBe('enumStructVariantTypeNode'); }); test('it returns a frozen object', () => { const node = enumStructVariantTypeNode('apple', structTypeNode([])); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/typeNodes/EnumTupleVariantTypeNode.test.ts ================================================ import { expect, test } from 'vitest'; import { enumTupleVariantTypeNode, tupleTypeNode } from '../../src'; test('it returns the right node kind', () => { const node = enumTupleVariantTypeNode('apple', tupleTypeNode([])); expect(node.kind).toBe('enumTupleVariantTypeNode'); }); test('it returns a frozen object', () => { const node = enumTupleVariantTypeNode('apple', tupleTypeNode([])); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/typeNodes/EnumTypeNode.test.ts ================================================ import { expect, test } from 'vitest'; import { enumTypeNode } from '../../src'; test('it returns the right node kind', () => { const node = enumTypeNode([]); expect(node.kind).toBe('enumTypeNode'); }); test('it returns a frozen object', () => { const node = enumTypeNode([]); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/typeNodes/FixedSizeTypeNode.test.ts ================================================ import { expect, test } from 'vitest'; import { fixedSizeTypeNode, stringTypeNode } from '../../src'; test('it returns the right node kind', () => { const node = fixedSizeTypeNode(stringTypeNode('utf8'), 42); expect(node.kind).toBe('fixedSizeTypeNode'); }); test('it returns a frozen object', () => { const node = fixedSizeTypeNode(stringTypeNode('utf8'), 42); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/typeNodes/HiddenPrefixTypeNode.test.ts ================================================ import { expect, test } from 'vitest'; import { hiddenPrefixTypeNode, numberTypeNode } from '../../src'; test('it returns the right node kind', () => { const node = hiddenPrefixTypeNode(numberTypeNode('u8'), []); expect(node.kind).toBe('hiddenPrefixTypeNode'); }); test('it returns a frozen object', () => { const node = hiddenPrefixTypeNode(numberTypeNode('u8'), []); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/typeNodes/HiddenSuffixTypeNode.test.ts ================================================ import { expect, test } from 'vitest'; import { hiddenSuffixTypeNode, numberTypeNode } from '../../src'; test('it returns the right node kind', () => { const node = hiddenSuffixTypeNode(numberTypeNode('u8'), []); expect(node.kind).toBe('hiddenSuffixTypeNode'); }); test('it returns a frozen object', () => { const node = hiddenSuffixTypeNode(numberTypeNode('u8'), []); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/typeNodes/MapTypeNode.test.ts ================================================ import { expect, test } from 'vitest'; import { mapTypeNode, numberTypeNode, remainderCountNode } from '../../src'; test('it returns the right node kind', () => { const node = mapTypeNode(numberTypeNode('u8'), numberTypeNode('u64'), remainderCountNode()); expect(node.kind).toBe('mapTypeNode'); }); test('it returns a frozen object', () => { const node = mapTypeNode(numberTypeNode('u8'), numberTypeNode('u64'), remainderCountNode()); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/typeNodes/NestedTypeNode.test.ts ================================================ import { describe, expect, test } from 'vitest'; import { assertIsNestedTypeNode, fixedSizeTypeNode, isNestedTypeNode, numberTypeNode, publicKeyTypeNode, resolveNestedTypeNode, sizePrefixTypeNode, stringTypeNode, transformNestedTypeNode, } from '../../src'; describe('resolveNestedTypeNode', () => { test('it resolved nested type nodes', () => { const node = sizePrefixTypeNode(fixedSizeTypeNode(stringTypeNode('utf8'), 32), numberTypeNode('u8')); expect(resolveNestedTypeNode(node)).toEqual(stringTypeNode('utf8')); }); test('it returns the same instance when resolving nested types nodes', () => { const node = numberTypeNode('u8'); expect(resolveNestedTypeNode(node)).toBe(node); }); }); describe('transformNestedTypeNode', () => { test('it transforms nested type nodes', () => { const node = sizePrefixTypeNode(fixedSizeTypeNode(stringTypeNode('utf8'), 32), numberTypeNode('u8')); const transformedNode = transformNestedTypeNode(node, () => publicKeyTypeNode()); expect(transformedNode).toEqual( sizePrefixTypeNode(fixedSizeTypeNode(publicKeyTypeNode(), 32), numberTypeNode('u8')), ); }); }); describe('isNestedTypeNode', () => { test('it checks if a node is a nested type', () => { const flatNode = numberTypeNode('u64'); expect(isNestedTypeNode(flatNode, 'numberTypeNode')).toBe(true); expect(isNestedTypeNode(flatNode, 'stringTypeNode')).toBe(false); const nestedNode = sizePrefixTypeNode(fixedSizeTypeNode(numberTypeNode('u64'), 32), numberTypeNode('u8')); expect(isNestedTypeNode(nestedNode, 'numberTypeNode')).toBe(true); expect(isNestedTypeNode(nestedNode, 'stringTypeNode')).toBe(false); }); }); describe('assertIsNestedTypeNode', () => { test('it asserts that a node is a nested type', () => { const flatNode = numberTypeNode('u64'); expect(() => assertIsNestedTypeNode(flatNode, 'numberTypeNode')).not.toThrow(); expect(() => assertIsNestedTypeNode(flatNode, 'stringTypeNode')).toThrow(); const nestedNode = sizePrefixTypeNode(fixedSizeTypeNode(numberTypeNode('u64'), 32), numberTypeNode('u8')); expect(() => assertIsNestedTypeNode(nestedNode, 'numberTypeNode')).not.toThrow(); expect(() => assertIsNestedTypeNode(nestedNode, 'stringTypeNode')).toThrow(); }); }); ================================================ FILE: packages/nodes/test/typeNodes/NestedTypeNode.typetest.ts ================================================ import { assertIsNestedTypeNode, fixedSizeTypeNode, isNestedTypeNode, NestedTypeNode, Node, NumberTypeNode, numberTypeNode, resolveNestedTypeNode, StringTypeNode, stringTypeNode, transformNestedTypeNode, } from '../../src'; // [DESCRIBE] NestedTypeNode. { // It constraints the nested type of a node. { const stringNestedNode = fixedSizeTypeNode(stringTypeNode('utf8'), 32); const numberNestedNode = fixedSizeTypeNode(numberTypeNode('u32'), 32); stringNestedNode satisfies NestedTypeNode; numberNestedNode satisfies NestedTypeNode; // @ts-expect-error The nested type is not a number. stringNestedNode satisfies NestedTypeNode; // @ts-expect-error The nested type is not a string. numberNestedNode satisfies NestedTypeNode; } } // [DESCRIBE] resolveNestedTypeNode. { // It unwraps the nested type of a node. { const stringNestedNode = fixedSizeTypeNode(stringTypeNode('utf8'), 32); const numberNestedNode = fixedSizeTypeNode(numberTypeNode('u32'), 32); resolveNestedTypeNode(stringNestedNode) satisfies StringTypeNode; resolveNestedTypeNode(numberNestedNode) satisfies NumberTypeNode; // @ts-expect-error The nested type is not a number. resolveNestedTypeNode(stringNestedNode) satisfies NumberTypeNode; // @ts-expect-error The nested type is not a string. resolveNestedTypeNode(numberNestedNode) satisfies StringTypeNode; } } // [DESCRIBE] transformNestedTypeNode. { // It transforms the nested type of a nested node. { const transformedNode = transformNestedTypeNode(fixedSizeTypeNode(stringTypeNode('utf8'), 32), () => numberTypeNode('u32'), ); transformedNode satisfies NestedTypeNode; // @ts-expect-error The nested type is not a number. transformedNode satisfies NestedTypeNode; } } // [DESCRIBE] isNestedTypeNode. { // It narrows the type of a node to a nested type node. { const node = {} as Node; if (isNestedTypeNode(node, 'numberTypeNode')) { node satisfies NestedTypeNode; // @ts-expect-error The nested type is not a string. node satisfies NestedTypeNode; } if (isNestedTypeNode(node, 'stringTypeNode')) { node satisfies NestedTypeNode; // @ts-expect-error The nested type is not a number. node satisfies NestedTypeNode; } } } // [DESCRIBE] assertIsNestedTypeNode. { // It narrows the type of a node to a nested type node. { { const node = {} as Node; assertIsNestedTypeNode(node, 'numberTypeNode'); node satisfies NestedTypeNode; // @ts-expect-error The nested type is not a string. node satisfies NestedTypeNode; } { const node = {} as Node; assertIsNestedTypeNode(node, 'stringTypeNode'); node satisfies NestedTypeNode; // @ts-expect-error The nested type is not a number. node satisfies NestedTypeNode; } } } ================================================ FILE: packages/nodes/test/typeNodes/NumberTypeNode.test.ts ================================================ import { expect, test } from 'vitest'; import { numberTypeNode } from '../../src'; test('it returns the right node kind', () => { const node = numberTypeNode('u8'); expect(node.kind).toBe('numberTypeNode'); }); test('it returns a frozen object', () => { const node = numberTypeNode('u8'); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/typeNodes/OptionTypeNode.test.ts ================================================ import { expect, test } from 'vitest'; import { numberTypeNode, optionTypeNode } from '../../src'; test('it returns the right node kind', () => { const node = optionTypeNode(numberTypeNode('u8')); expect(node.kind).toBe('optionTypeNode'); }); test('it returns a frozen object', () => { const node = optionTypeNode(numberTypeNode('u8')); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/typeNodes/PostOffsetTypeNode.test.ts ================================================ import { expect, test } from 'vitest'; import { numberTypeNode, postOffsetTypeNode } from '../../src'; test('it returns the right node kind', () => { const node = postOffsetTypeNode(numberTypeNode('u8'), 42); expect(node.kind).toBe('postOffsetTypeNode'); }); test('it returns a frozen object', () => { const node = postOffsetTypeNode(numberTypeNode('u8'), 42); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/typeNodes/PreOffsetTypeNode.test.ts ================================================ import { expect, test } from 'vitest'; import { numberTypeNode, preOffsetTypeNode } from '../../src'; test('it returns the right node kind', () => { const node = preOffsetTypeNode(numberTypeNode('u8'), 42); expect(node.kind).toBe('preOffsetTypeNode'); }); test('it returns a frozen object', () => { const node = preOffsetTypeNode(numberTypeNode('u8'), 42); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/typeNodes/PublicKeyTypeNode.test.ts ================================================ import { expect, test } from 'vitest'; import { publicKeyTypeNode } from '../../src'; test('it returns the right node kind', () => { const node = publicKeyTypeNode(); expect(node.kind).toBe('publicKeyTypeNode'); }); test('it returns a frozen object', () => { const node = publicKeyTypeNode(); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/typeNodes/RemainderOptionTypeNode.test.ts ================================================ import { expect, test } from 'vitest'; import { numberTypeNode, remainderOptionTypeNode } from '../../src'; test('it returns the right node kind', () => { const node = remainderOptionTypeNode(numberTypeNode('u8')); expect(node.kind).toBe('remainderOptionTypeNode'); }); test('it returns a frozen object', () => { const node = remainderOptionTypeNode(numberTypeNode('u8')); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/typeNodes/SentinelTypeNode.test.ts ================================================ import { expect, test } from 'vitest'; import { constantValueNodeFromBytes, sentinelTypeNode, stringTypeNode } from '../../src'; test('it returns the right node kind', () => { const node = sentinelTypeNode(stringTypeNode('utf8'), constantValueNodeFromBytes('base16', 'ff')); expect(node.kind).toBe('sentinelTypeNode'); }); test('it returns a frozen object', () => { const node = sentinelTypeNode(stringTypeNode('utf8'), constantValueNodeFromBytes('base16', 'ff')); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/typeNodes/SetTypeNode.test.ts ================================================ import { expect, test } from 'vitest'; import { numberTypeNode, remainderCountNode, setTypeNode } from '../../src'; test('it returns the right node kind', () => { const node = setTypeNode(numberTypeNode('u64'), remainderCountNode()); expect(node.kind).toBe('setTypeNode'); }); test('it returns a frozen object', () => { const node = setTypeNode(numberTypeNode('u64'), remainderCountNode()); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/typeNodes/SizePrefixTypeNode.test.ts ================================================ import { expect, test } from 'vitest'; import { numberTypeNode, sizePrefixTypeNode, stringTypeNode } from '../../src'; test('it returns the right node kind', () => { const node = sizePrefixTypeNode(stringTypeNode('utf8'), numberTypeNode('u32')); expect(node.kind).toBe('sizePrefixTypeNode'); }); test('it returns a frozen object', () => { const node = sizePrefixTypeNode(stringTypeNode('utf8'), numberTypeNode('u32')); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/typeNodes/SolAmountTypeNode.test.ts ================================================ import { expect, test } from 'vitest'; import { numberTypeNode, solAmountTypeNode } from '../../src'; test('it returns the right node kind', () => { const node = solAmountTypeNode(numberTypeNode('u32')); expect(node.kind).toBe('solAmountTypeNode'); }); test('it returns a frozen object', () => { const node = solAmountTypeNode(numberTypeNode('u32')); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/typeNodes/StringTypeNode.test.ts ================================================ import { expect, test } from 'vitest'; import { stringTypeNode } from '../../src'; test('it returns the right node kind', () => { const node = stringTypeNode('utf8'); expect(node.kind).toBe('stringTypeNode'); }); test('it returns a frozen object', () => { const node = stringTypeNode('utf8'); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/typeNodes/StructFieldTypeNode.test.ts ================================================ import { expect, test } from 'vitest'; import { numberTypeNode, structFieldTypeNode } from '../../src'; test('it returns the right node kind', () => { const node = structFieldTypeNode({ name: 'age', type: numberTypeNode('u8') }); expect(node.kind).toBe('structFieldTypeNode'); }); test('it returns a frozen object', () => { const node = structFieldTypeNode({ name: 'age', type: numberTypeNode('u8') }); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/typeNodes/StructTypeNode.test.ts ================================================ import { expect, test } from 'vitest'; import { structTypeNode } from '../../src'; test('it returns the right node kind', () => { const node = structTypeNode([]); expect(node.kind).toBe('structTypeNode'); }); test('it returns a frozen object', () => { const node = structTypeNode([]); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/typeNodes/TupleTypeNode.test.ts ================================================ import { expect, test } from 'vitest'; import { tupleTypeNode } from '../../src'; test('it returns the right node kind', () => { const node = tupleTypeNode([]); expect(node.kind).toBe('tupleTypeNode'); }); test('it returns a frozen object', () => { const node = tupleTypeNode([]); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/typeNodes/TypeNode.typetest.ts ================================================ import type { RegisteredTypeNode } from '@codama/node-types'; import { REGISTERED_TYPE_NODE_KINDS } from '../../src'; // [DESCRIBE] Registered value node kinds. { // It matches exactly with RegisteredTypeNode['kind']. { REGISTERED_TYPE_NODE_KINDS satisfies readonly RegisteredTypeNode['kind'][]; null as unknown as RegisteredTypeNode['kind'] satisfies (typeof REGISTERED_TYPE_NODE_KINDS)[number]; } } ================================================ FILE: packages/nodes/test/typeNodes/ZeroableOptionTypeNode.test.ts ================================================ import { expect, test } from 'vitest'; import { publicKeyTypeNode, zeroableOptionTypeNode } from '../../src'; test('it returns the right node kind', () => { const node = zeroableOptionTypeNode(publicKeyTypeNode()); expect(node.kind).toBe('zeroableOptionTypeNode'); }); test('it returns a frozen object', () => { const node = zeroableOptionTypeNode(publicKeyTypeNode()); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/types/global.d.ts ================================================ declare const __BROWSER__: boolean; declare const __ESM__: boolean; declare const __NODEJS__: boolean; declare const __REACTNATIVE__: boolean; declare const __TEST__: boolean; declare const __VERSION__: string; ================================================ FILE: packages/nodes/test/valueNodes/ArrayValueNode.test.ts ================================================ import { expect, test } from 'vitest'; import { arrayValueNode } from '../../src'; test('it returns the right node kind', () => { const node = arrayValueNode([]); expect(node.kind).toBe('arrayValueNode'); }); test('it returns a frozen object', () => { const node = arrayValueNode([]); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/valueNodes/BooleanValueNode.test.ts ================================================ import { expect, test } from 'vitest'; import { booleanValueNode } from '../../src'; test('it returns the right node kind', () => { const node = booleanValueNode(true); expect(node.kind).toBe('booleanValueNode'); }); test('it returns a frozen object', () => { const node = booleanValueNode(true); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/valueNodes/BytesValueNode.test.ts ================================================ import { expect, test } from 'vitest'; import { bytesValueNode } from '../../src'; test('it returns the right node kind', () => { const node = bytesValueNode('utf8', 'hello world'); expect(node.kind).toBe('bytesValueNode'); }); test('it returns a frozen object', () => { const node = bytesValueNode('utf8', 'hello world'); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/valueNodes/ConstantValueNode.test.ts ================================================ import { expect, test } from 'vitest'; import { constantValueNode, numberTypeNode, numberValueNode } from '../../src'; test('it returns the right node kind', () => { const node = constantValueNode(numberTypeNode('u8'), numberValueNode(42)); expect(node.kind).toBe('constantValueNode'); }); test('it returns a frozen object', () => { const node = constantValueNode(numberTypeNode('u8'), numberValueNode(42)); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/valueNodes/EnumValueNode.test.ts ================================================ import { expect, test } from 'vitest'; import { enumValueNode } from '../../src'; test('it returns the right node kind', () => { const node = enumValueNode('fruit', 'apple'); expect(node.kind).toBe('enumValueNode'); }); test('it returns a frozen object', () => { const node = enumValueNode('fruit', 'apple'); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/valueNodes/MapEntryValueNode.test.ts ================================================ import { expect, test } from 'vitest'; import { mapEntryValueNode, numberValueNode, stringValueNode } from '../../src'; test('it returns the right node kind', () => { const node = mapEntryValueNode(stringValueNode('age'), numberValueNode(42)); expect(node.kind).toBe('mapEntryValueNode'); }); test('it returns a frozen object', () => { const node = mapEntryValueNode(stringValueNode('age'), numberValueNode(42)); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/valueNodes/MapValueNode.test.ts ================================================ import { expect, test } from 'vitest'; import { mapValueNode } from '../../src'; test('it returns the right node kind', () => { const node = mapValueNode([]); expect(node.kind).toBe('mapValueNode'); }); test('it returns a frozen object', () => { const node = mapValueNode([]); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/valueNodes/NoneValueNode.test.ts ================================================ import { expect, test } from 'vitest'; import { noneValueNode } from '../../src'; test('it returns the right node kind', () => { const node = noneValueNode(); expect(node.kind).toBe('noneValueNode'); }); test('it returns a frozen object', () => { const node = noneValueNode(); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/valueNodes/NumberValueNode.test.ts ================================================ import { expect, test } from 'vitest'; import { numberValueNode } from '../../src'; test('it returns the right node kind', () => { const node = numberValueNode(42); expect(node.kind).toBe('numberValueNode'); }); test('it returns a frozen object', () => { const node = numberValueNode(42); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/valueNodes/PublicKeyValueNode.test.ts ================================================ import { expect, test } from 'vitest'; import { publicKeyValueNode } from '../../src'; test('it returns the right node kind', () => { const node = publicKeyValueNode('1111'); expect(node.kind).toBe('publicKeyValueNode'); }); test('it returns a frozen object', () => { const node = publicKeyValueNode('1111'); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/valueNodes/SetValueNode.test.ts ================================================ import { expect, test } from 'vitest'; import { setValueNode } from '../../src'; test('it returns the right node kind', () => { const node = setValueNode([]); expect(node.kind).toBe('setValueNode'); }); test('it returns a frozen object', () => { const node = setValueNode([]); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/valueNodes/SomeValueNode.test.ts ================================================ import { expect, test } from 'vitest'; import { numberValueNode, someValueNode } from '../../src'; test('it returns the right node kind', () => { const node = someValueNode(numberValueNode(42)); expect(node.kind).toBe('someValueNode'); }); test('it returns a frozen object', () => { const node = someValueNode(numberValueNode(42)); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/valueNodes/StringValueNode.test.ts ================================================ import { expect, test } from 'vitest'; import { stringValueNode } from '../../src'; test('it returns the right node kind', () => { const node = stringValueNode('hello world'); expect(node.kind).toBe('stringValueNode'); }); test('it returns a frozen object', () => { const node = stringValueNode('hello world'); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/valueNodes/StructFieldValueNode.test.ts ================================================ import { expect, test } from 'vitest'; import { stringValueNode, structFieldValueNode } from '../../src'; test('it returns the right node kind', () => { const node = structFieldValueNode('name', stringValueNode('Alice')); expect(node.kind).toBe('structFieldValueNode'); }); test('it returns a frozen object', () => { const node = structFieldValueNode('name', stringValueNode('Alice')); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/valueNodes/StructValueNode.test.ts ================================================ import { expect, test } from 'vitest'; import { structValueNode } from '../../src'; test('it returns the right node kind', () => { const node = structValueNode([]); expect(node.kind).toBe('structValueNode'); }); test('it returns a frozen object', () => { const node = structValueNode([]); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/valueNodes/TupleValueNode.test.ts ================================================ import { expect, test } from 'vitest'; import { tupleValueNode } from '../../src'; test('it returns the right node kind', () => { const node = tupleValueNode([]); expect(node.kind).toBe('tupleValueNode'); }); test('it returns a frozen object', () => { const node = tupleValueNode([]); expect(Object.isFrozen(node)).toBe(true); }); ================================================ FILE: packages/nodes/test/valueNodes/ValueNode.typetest.ts ================================================ import type { RegisteredValueNode } from '@codama/node-types'; import { REGISTERED_VALUE_NODE_KINDS } from '../../src'; // [DESCRIBE] Registered value node kinds. { // It matches exactly with RegisteredValueNode['kind']. { REGISTERED_VALUE_NODE_KINDS satisfies readonly RegisteredValueNode['kind'][]; null as unknown as RegisteredValueNode['kind'] satisfies (typeof REGISTERED_VALUE_NODE_KINDS)[number]; } } ================================================ FILE: packages/nodes/tsconfig.declarations.json ================================================ { "compilerOptions": { "declaration": true, "declarationMap": true, "emitDeclarationOnly": true, "outDir": "./dist/types" }, "extends": "./tsconfig.json", "include": ["src/index.ts", "src/types"] } ================================================ FILE: packages/nodes/tsconfig.json ================================================ { "$schema": "https://json.schemastore.org/tsconfig", "compilerOptions": { "lib": [] }, "display": "@codama/nodes", "extends": "../../tsconfig.json", "include": ["src", "test"] } ================================================ FILE: packages/nodes/tsup.config.ts ================================================ import { defineConfig } from 'tsup'; import { getPackageBuildConfigs } from '../../tsup.config.base'; export default defineConfig(getPackageBuildConfigs()); ================================================ FILE: packages/nodes/vitest.config.mts ================================================ import { defineConfig } from 'vitest/config'; import { getVitestConfig } from '../../vitest.config.base.mjs'; export default defineConfig({ test: { projects: [getVitestConfig('browser'), getVitestConfig('node'), getVitestConfig('react-native')], }, }); ================================================ FILE: packages/nodes-from-anchor/.gitignore ================================================ dist/ ================================================ FILE: packages/nodes-from-anchor/.prettierignore ================================================ dist/ test/e2e/ test-ledger/ target/ CHANGELOG.md ================================================ FILE: packages/nodes-from-anchor/LICENSE ================================================ MIT License Copyright (c) 2025 Codama Copyright (c) 2024 Metaplex Foundation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: packages/nodes-from-anchor/README.md ================================================ # Codama ➤ Nodes From Anchor [![npm][npm-image]][npm-url] [![npm-downloads][npm-downloads-image]][npm-url] [npm-downloads-image]: https://img.shields.io/npm/dm/@codama/nodes-from-anchor.svg?style=flat [npm-image]: https://img.shields.io/npm/v/@codama/nodes-from-anchor.svg?style=flat&label=%40codama%2Fnodes-from-anchor [npm-url]: https://www.npmjs.com/package/@codama/nodes-from-anchor This package converts Anchor IDLs from various versions into Codama IDLs. ## Installation ```sh pnpm install @codama/nodes-from-anchor ``` > [!NOTE] > > - This package is **not** included in the main [`codama`](../library) package. > - If `metadata.origin` is not set on the IDL, it is assumed to be `"anchor"`. If you are trying to parse a Shank IDL, be sure that origin is set to `"shank"` so discriminators can be set correctly. ## Functions ### `rootNodeFromAnchor(anchorIdl)` This function takes a valid Anchor IDL and returns a `RootNode`. ```js // node ./codama.mjs import { rootNodeFromAnchor } from '@codama/nodes-from-anchor'; import { createFromRoot } from 'codama'; import { readFileSync } from 'node:fs'; import path from 'path'; // Read the content of your IDL file. const anchorIdlPath = path.join(__dirname, 'target', 'idl', 'anchor_program.json'); const anchorIdl = JSON.parse(readFileSync(anchorIdlPath, 'utf-8')); // Parse it into a Codama IDL. const codama = createFromRoot(rootNodeFromAnchor(anchorIdl)); ``` ================================================ FILE: packages/nodes-from-anchor/package.json ================================================ { "name": "@codama/nodes-from-anchor", "version": "1.4.1", "description": "Node specifications and helpers for the Codama standard", "exports": { "types": "./dist/types/index.d.ts", "react-native": "./dist/index.react-native.mjs", "browser": { "import": "./dist/index.browser.mjs", "require": "./dist/index.browser.cjs" }, "node": { "import": "./dist/index.node.mjs", "require": "./dist/index.node.cjs" } }, "browser": { "./dist/index.node.cjs": "./dist/index.browser.cjs", "./dist/index.node.mjs": "./dist/index.browser.mjs" }, "main": "./dist/index.node.cjs", "module": "./dist/index.node.mjs", "react-native": "./dist/index.react-native.mjs", "types": "./dist/types/index.d.ts", "type": "commonjs", "files": [ "./dist/types", "./dist/index.*" ], "sideEffects": false, "keywords": [ "solana", "framework", "standard", "specifications" ], "scripts": { "build": "rimraf dist && tsup && tsc -p ./tsconfig.declarations.json", "dev": "vitest --project node", "lint": "eslint . && prettier --check .", "lint:fix": "eslint --fix . && prettier --write .", "test": "pnpm test:types && pnpm test:treeshakability && pnpm test:unit", "test:treeshakability": "for file in dist/index.*.mjs; do agadoo $file; done", "test:types": "tsc --noEmit", "test:unit": "vitest run" }, "dependencies": { "@codama/errors": "workspace:*", "@codama/nodes": "workspace:*", "@codama/visitors": "workspace:*", "@solana/codecs": "^5.3.0", "@noble/hashes": "^2.0.1" }, "license": "MIT", "repository": { "type": "git", "url": "https://github.com/codama-idl/codama" }, "bugs": { "url": "http://github.com/codama-idl/codama/issues" }, "browserslist": [ "supports bigint and not dead", "maintained node versions" ] } ================================================ FILE: packages/nodes-from-anchor/src/defaultVisitor.ts ================================================ import { assertIsNode, Node, RootNode } from '@codama/nodes'; import { deduplicateIdenticalDefinedTypesVisitor, flattenInstructionDataArgumentsVisitor, getCommonInstructionAccountDefaultRules, rootNodeVisitor, setFixedAccountSizesVisitor, setInstructionAccountDefaultValuesVisitor, transformU8ArraysToBytesVisitor, unwrapInstructionArgsDefinedTypesVisitor, visit, Visitor, } from '@codama/visitors'; import { extractPdasVisitor } from './extractPdasVisitor'; export function defaultVisitor() { return rootNodeVisitor(currentRoot => { let root: RootNode = currentRoot; const updateRoot = (visitor: Visitor) => { const newRoot = visit(root, visitor); assertIsNode(newRoot, 'rootNode'); root = newRoot; }; // PDAs. updateRoot(extractPdasVisitor()); // Defined types. updateRoot(deduplicateIdenticalDefinedTypesVisitor()); // Accounts. updateRoot(setFixedAccountSizesVisitor()); // Instructions. updateRoot(setInstructionAccountDefaultValuesVisitor(getCommonInstructionAccountDefaultRules())); updateRoot(unwrapInstructionArgsDefinedTypesVisitor()); updateRoot(flattenInstructionDataArgumentsVisitor()); // Extras. updateRoot(transformU8ArraysToBytesVisitor()); return root; }); } ================================================ FILE: packages/nodes-from-anchor/src/discriminators.ts ================================================ import { BytesValueNode, bytesValueNode, pascalCase, snakeCase } from '@codama/nodes'; import { sha256 } from '@noble/hashes/sha2.js'; import { getUtf8Codec } from '@solana/codecs'; import { hex } from './utils'; export const getAnchorDiscriminatorV01 = (discriminator: number[]): BytesValueNode => { return bytesValueNode('base16', hex(new Uint8Array(discriminator))); }; export const getAnchorInstructionDiscriminatorV00 = (idlName: string): BytesValueNode => { const bytes = getUtf8Codec().encode(`global:${snakeCase(idlName)}`); const hash = sha256(bytes as Uint8Array).slice(0, 8); return bytesValueNode('base16', hex(hash)); }; export const getAnchorAccountDiscriminatorV00 = (idlName: string): BytesValueNode => { const bytes = getUtf8Codec().encode(`account:${pascalCase(idlName)}`); const hash = sha256(bytes as Uint8Array).slice(0, 8); return bytesValueNode('base16', hex(hash)); }; ================================================ FILE: packages/nodes-from-anchor/src/extractPdasVisitor.ts ================================================ import { logWarn } from '@codama/errors'; import { assertIsNode, camelCase, type CamelCaseString, instructionAccountNode, type InstructionNode, instructionNode, isNode, pdaLinkNode, type PdaNode, pdaNode, type ProgramNode, programNode, } from '@codama/nodes'; import { bottomUpTransformerVisitor, getUniqueHashStringVisitor, visit, type Visitor } from '@codama/visitors'; type Fingerprint = string; function pdaFingerprint(pda: PdaNode, hashVisitor: Visitor): Fingerprint { return visit(pdaNode({ ...pda, name: '' }), hashVisitor); } function getUniquePdaName(name: CamelCaseString, usedNames: Set): CamelCaseString { if (!usedNames.has(name)) return name; let suffix = 2; let candidate = camelCase(`${name}${suffix}`); while (usedNames.has(candidate)) { suffix++; candidate = camelCase(`${name}${suffix}`); } return candidate; } export function extractPdasVisitor() { return bottomUpTransformerVisitor([ { select: '[programNode]', transform: node => { assertIsNode(node, 'programNode'); return extractPdasFromProgram(node); }, }, ]); } export function extractPdasFromProgram(program: ProgramNode): ProgramNode { const hashVisitor = getUniqueHashStringVisitor(); const pdaMap = new Map(); const usedNames = new Set(program.pdas.map(p => p.name)); const nameToFingerprint = new Map(); const rewrittenInstructions = program.instructions.map(instruction => { const rewrittenAccounts = instruction.accounts.map(account => { if ( !account.defaultValue || !isNode(account.defaultValue, 'pdaValueNode') || !isNode(account.defaultValue.pda, 'pdaNode') ) { return account; } const pda = account.defaultValue.pda; if (pda.programId && pda.programId !== program.publicKey) return account; const fingerprint = pdaFingerprint(pda, hashVisitor); if (!pdaMap.has(fingerprint)) { let resolvedName = pda.name; const existingFingerprint = nameToFingerprint.get(resolvedName); if (existingFingerprint !== undefined && existingFingerprint !== fingerprint) { resolvedName = camelCase(`${instruction.name}_${pda.name}`); logWarn( `PDA name collision: "${pda.name}" has different seeds across instructions. ` + `Renaming to "${resolvedName}".`, ); } resolvedName = getUniquePdaName(resolvedName, usedNames); usedNames.add(resolvedName); nameToFingerprint.set(resolvedName, fingerprint); pdaMap.set(fingerprint, pdaNode({ ...pda, name: resolvedName })); } const extractedPda = pdaMap.get(fingerprint)!; const defaultValue = { ...account.defaultValue, pda: pdaLinkNode(extractedPda.name) }; return instructionAccountNode({ ...account, defaultValue }); }); return instructionNode({ ...instruction, accounts: rewrittenAccounts, }) as InstructionNode; }); return programNode({ ...program, instructions: rewrittenInstructions, pdas: [...program.pdas, ...pdaMap.values()], }); } ================================================ FILE: packages/nodes-from-anchor/src/index.ts ================================================ import { RootNode } from '@codama/nodes'; import { visit } from '@codama/visitors'; import { defaultVisitor } from './defaultVisitor'; import { IdlV00, rootNodeFromAnchorV00 } from './v00'; import { IdlV01, rootNodeFromAnchorV01 } from './v01'; export * from './defaultVisitor'; export * from './discriminators'; export * from './extractPdasVisitor'; export * from './v00'; export * from './v01'; export type AnchorIdl = IdlV00 | IdlV01; export function rootNodeFromAnchor(idl: AnchorIdl): RootNode { return visit(rootNodeFromAnchorWithoutDefaultVisitor(idl), defaultVisitor()); } export function rootNodeFromAnchorWithoutDefaultVisitor(idl: AnchorIdl): RootNode { if ((idl.metadata as { spec?: string })?.spec === '0.1.0') { return rootNodeFromAnchorV01(idl as IdlV01); } return rootNodeFromAnchorV00(idl as IdlV00); } ================================================ FILE: packages/nodes-from-anchor/src/utils.ts ================================================ export function hex(bytes: number[] | Uint8Array): string { return (bytes as number[]).reduce((str, byte) => str + byte.toString(16).padStart(2, '0'), ''); } ================================================ FILE: packages/nodes-from-anchor/src/v00/AccountNode.ts ================================================ import { AccountNode, accountNode, assertIsNode, bytesTypeNode, camelCase, DiscriminatorNode, fieldDiscriminatorNode, fixedSizeTypeNode, pdaLinkNode, structFieldTypeNode, StructTypeNode, structTypeNode, } from '@codama/nodes'; import { getAnchorAccountDiscriminatorV00 } from '../discriminators'; import { IdlV00AccountDef } from './idl'; import { structTypeNodeFromAnchorV00 } from './typeNodes'; export function accountNodeFromAnchorV00( idl: IdlV00AccountDef, origin?: 'anchor' | 'shank', ): AccountNode { const idlName = idl.name ?? ''; const name = camelCase(idlName); const idlStruct = idl.type ?? { fields: [], kind: 'struct' }; let data = structTypeNodeFromAnchorV00(idlStruct); assertIsNode(data, 'structTypeNode'); const hasSeeds = (idl.seeds ?? []).length > 0; // Account discriminator. let discriminators: DiscriminatorNode[] | undefined; if (origin === 'anchor') { const discriminator = structFieldTypeNode({ defaultValue: getAnchorAccountDiscriminatorV00(idlName), defaultValueStrategy: 'omitted', name: 'discriminator', type: fixedSizeTypeNode(bytesTypeNode(), 8), }); data = structTypeNode([discriminator, ...data.fields]); discriminators = [fieldDiscriminatorNode('discriminator')]; } return accountNode({ data, discriminators, docs: idl.docs ?? [], name, pda: hasSeeds ? pdaLinkNode(name) : undefined, size: idl.size, }); } ================================================ FILE: packages/nodes-from-anchor/src/v00/DefinedTypeNode.ts ================================================ import { DefinedTypeNode, definedTypeNode } from '@codama/nodes'; import { IdlV00TypeDef } from './idl'; import { typeNodeFromAnchorV00 } from './typeNodes'; export function definedTypeNodeFromAnchorV00(idl: Partial): DefinedTypeNode { const name = idl.name ?? ''; const idlType = idl.type ?? { fields: [], kind: 'struct' }; const type = typeNodeFromAnchorV00(idlType); return definedTypeNode({ docs: idl.docs, name, type }); } ================================================ FILE: packages/nodes-from-anchor/src/v00/ErrorNode.ts ================================================ import { ErrorNode, errorNode } from '@codama/nodes'; import { IdlV00ErrorCode } from './idl'; export function errorNodeFromAnchorV00(idl: Partial): ErrorNode { const name = idl.name ?? ''; const msg = idl.msg ?? ''; return errorNode({ code: idl.code ?? -1, docs: idl.docs ?? [msg ? `${name}: ${msg}` : `${name}`], message: msg, name, }); } ================================================ FILE: packages/nodes-from-anchor/src/v00/InstructionAccountNode.ts ================================================ import { camelCase, InstructionAccountNode, instructionAccountNode } from '@codama/nodes'; import { IdlV00Account, IdlV00AccountItem } from './idl'; function hasDuplicateAccountNames(idl: IdlV00AccountItem[]): boolean { const seenNames = new Set(); function checkDuplicates(items: IdlV00AccountItem[]): boolean { for (const item of items) { if ('accounts' in item) { if (checkDuplicates(item.accounts)) { return true; } } else { const name = camelCase(item.name ?? ''); if (seenNames.has(name)) { return true; } seenNames.add(name); } } return false; } return checkDuplicates(idl); } export function instructionAccountNodesFromAnchorV00( idl: IdlV00AccountItem[], prefix?: string, ): InstructionAccountNode[] { const shouldPrefix = prefix !== undefined || hasDuplicateAccountNames(idl); return idl.flatMap(account => 'accounts' in account ? instructionAccountNodesFromAnchorV00( account.accounts, shouldPrefix ? (prefix ? `${prefix}_${account.name}` : account.name) : undefined, ) : [instructionAccountNodeFromAnchorV00(account, shouldPrefix ? prefix : undefined)], ); } export function instructionAccountNodeFromAnchorV00(idl: IdlV00Account, prefix?: string): InstructionAccountNode { const isOptional = idl.optional ?? idl.isOptional ?? false; const desc = idl.desc ? [idl.desc] : undefined; return instructionAccountNode({ docs: idl.docs ?? desc ?? [], isOptional, isSigner: idl.isOptionalSigner ? 'either' : (idl.isSigner ?? false), isWritable: idl.isMut ?? false, name: prefix ? `${prefix}_${idl.name ?? ''}` : (idl.name ?? ''), }); } ================================================ FILE: packages/nodes-from-anchor/src/v00/InstructionArgumentNode.ts ================================================ import { InstructionArgumentNode, instructionArgumentNode } from '@codama/nodes'; import { IdlV00Field } from './idl'; import { typeNodeFromAnchorV00 } from './typeNodes'; export function instructionArgumentNodeFromAnchorV00(idl: IdlV00Field): InstructionArgumentNode { return instructionArgumentNode({ docs: idl.docs ?? [], name: idl.name ?? '', type: typeNodeFromAnchorV00(idl.type), }); } ================================================ FILE: packages/nodes-from-anchor/src/v00/InstructionNode.ts ================================================ import { bytesTypeNode, bytesValueNode, camelCase, DiscriminatorNode, fieldDiscriminatorNode, fixedSizeTypeNode, instructionArgumentNode, InstructionNode, instructionNode, numberValueNode, } from '@codama/nodes'; import { getAnchorInstructionDiscriminatorV00 } from '../discriminators'; import { IdlV00Instruction } from './idl'; import { instructionAccountNodesFromAnchorV00 } from './InstructionAccountNode'; import { instructionArgumentNodeFromAnchorV00 } from './InstructionArgumentNode'; import { typeNodeFromAnchorV00 } from './typeNodes'; export function instructionNodeFromAnchorV00( idl: IdlV00Instruction, ixIndex: number, origin?: 'anchor' | 'shank', ): InstructionNode { const idlName = idl.name ?? ''; const name = camelCase(idlName); let dataArguments = (idl.args ?? []).map(instructionArgumentNodeFromAnchorV00); // Instruction discriminator. let discriminators: DiscriminatorNode[] | undefined; if (idl.discriminant) { const discriminatorField = instructionArgumentNode({ defaultValue: numberValueNode(idl.discriminant.value), defaultValueStrategy: 'omitted', name: 'discriminator', type: typeNodeFromAnchorV00(idl.discriminant.type), }); dataArguments = [discriminatorField, ...dataArguments]; discriminators = [fieldDiscriminatorNode('discriminator')]; } else if (origin === 'anchor') { const discriminatorField = instructionArgumentNode({ defaultValue: getAnchorInstructionDiscriminatorV00(idlName), defaultValueStrategy: 'omitted', name: 'discriminator', type: fixedSizeTypeNode(bytesTypeNode(), 8), }); dataArguments = [discriminatorField, ...dataArguments]; discriminators = [fieldDiscriminatorNode('discriminator')]; } else if (origin === 'shank') { const discriminatorField = instructionArgumentNode({ defaultValue: bytesValueNode('base16', ixIndex.toString(16)), defaultValueStrategy: 'omitted', name: 'discriminator', type: fixedSizeTypeNode(bytesTypeNode(), 1), }); dataArguments = [discriminatorField, ...dataArguments]; discriminators = [fieldDiscriminatorNode('discriminator')]; } return instructionNode({ accounts: instructionAccountNodesFromAnchorV00(idl.accounts ?? []), arguments: dataArguments, discriminators, docs: idl.docs ?? [], name, optionalAccountStrategy: idl.legacyOptionalAccountsStrategy ? 'omitted' : 'programId', }); } ================================================ FILE: packages/nodes-from-anchor/src/v00/PdaNode.ts ================================================ import { booleanValueNode, bytesTypeNode, camelCase, constantPdaSeedNode, constantPdaSeedNodeFromProgramId, numberValueNode, PdaNode, pdaNode, PdaSeedNode, stringTypeNode, stringValueNode, variablePdaSeedNode, } from '@codama/nodes'; import { IdlV00PdaDef } from './idl'; import { typeNodeFromAnchorV00 } from './typeNodes'; export function pdaNodeFromAnchorV00(idl: IdlV00PdaDef): PdaNode { const name = camelCase(idl.name ?? ''); const seeds = (idl.seeds ?? []).map((seed): PdaSeedNode => { if (seed.kind === 'constant') { const type = (() => { if (seed.type === 'string') return stringTypeNode('utf8'); if (seed.type === 'bytes') return bytesTypeNode(); return typeNodeFromAnchorV00(seed.type); })(); const value = (() => { if (typeof seed.value === 'string') return stringValueNode(seed.value); if (typeof seed.value === 'number') return numberValueNode(seed.value); return booleanValueNode(seed.value); })(); return constantPdaSeedNode(type, value); } if (seed.kind === 'variable') { return variablePdaSeedNode( seed.name, typeNodeFromAnchorV00(seed.type), seed.description ? [seed.description] : [], ); } return constantPdaSeedNodeFromProgramId(); }); return pdaNode({ name, seeds }); } ================================================ FILE: packages/nodes-from-anchor/src/v00/ProgramNode.ts ================================================ import { ProgramNode, programNode, ProgramVersion } from '@codama/nodes'; import { accountNodeFromAnchorV00 } from './AccountNode'; import { definedTypeNodeFromAnchorV00 } from './DefinedTypeNode'; import { errorNodeFromAnchorV00 } from './ErrorNode'; import { IdlV00 } from './idl'; import { instructionNodeFromAnchorV00 } from './InstructionNode'; import { pdaNodeFromAnchorV00 } from './PdaNode'; export function programNodeFromAnchorV00(idl: IdlV00): ProgramNode { const origin = (idl?.metadata as { origin?: 'anchor' | 'shank' })?.origin ?? 'anchor'; const pdas = (idl.accounts ?? []).filter(account => (account.seeds ?? []).length > 0).map(pdaNodeFromAnchorV00); const accounts = (idl.accounts ?? []).map(a => accountNodeFromAnchorV00(a, origin)); const instructions = (idl.instructions ?? []).map((instruction, index) => instructionNodeFromAnchorV00(instruction, index, origin), ); return programNode({ accounts, definedTypes: (idl?.types ?? []).map(definedTypeNodeFromAnchorV00), errors: (idl?.errors ?? []).map(errorNodeFromAnchorV00), instructions, name: idl?.name ?? '', origin, pdas, publicKey: (idl?.metadata as { address?: string })?.address ?? '', version: idl.version as ProgramVersion, }); } ================================================ FILE: packages/nodes-from-anchor/src/v00/RootNode.ts ================================================ import { RootNode, rootNode } from '@codama/nodes'; import { IdlV00 } from './idl'; import { programNodeFromAnchorV00 } from './ProgramNode'; export function rootNodeFromAnchorV00(program: IdlV00, additionalPrograms: IdlV00[] = []): RootNode { const programNode = programNodeFromAnchorV00(program); const additionalProgramNodes = additionalPrograms.map(programNodeFromAnchorV00); return rootNode(programNode, additionalProgramNodes); } ================================================ FILE: packages/nodes-from-anchor/src/v00/idl.ts ================================================ export type IdlV00 = { accounts?: IdlV00AccountDef[]; constants?: IdlV00Constant[]; docs?: string[]; errors?: IdlV00ErrorCode[]; events?: IdlV00Event[]; instructions: IdlV00Instruction[]; metadata?: IdlV00Metadata; name: string; types?: IdlV00TypeDef[]; version: string; }; export type IdlV00Metadata = object; export type IdlV00Constant = { name: string; type: IdlV00Type; value: string; }; export type IdlV00Event = { fields: IdlV00EventField[]; name: string; }; export type IdlV00EventField = { index: boolean; name: string; type: IdlV00Type; }; export type IdlV00Instruction = { accounts: IdlV00AccountItem[]; args: IdlV00Field[]; discriminant?: IdlV00InstructionDiscriminant; docs?: string[]; legacyOptionalAccountsStrategy?: boolean; name: string; returns?: IdlV00Type; }; export type IdlV00InstructionDiscriminant = { type: IdlV00Type; value: number; }; export type IdlV00StateMethod = IdlV00Instruction; export type IdlV00AccountItem = IdlV00Account | IdlV00Accounts; export type IdlV00Account = { desc?: string; docs?: string[]; isMut: boolean; isOptional?: boolean; isOptionalSigner?: boolean; isSigner: boolean; name: string; optional?: boolean; pda?: IdlV00Pda; relations?: string[]; }; export type IdlV00Pda = { programId?: IdlV00Seed; seeds: IdlV00Seed[]; }; export type IdlV00Seed = IdlV00SeedAccount | IdlV00SeedArg | IdlV00SeedConst; export type IdlV00SeedConst = { kind: 'const'; type: IdlV00Type; // eslint-disable-next-line @typescript-eslint/no-explicit-any value: any; }; export type IdlV00SeedArg = { kind: 'arg'; path: string; type: IdlV00Type; }; export type IdlV00SeedAccount = { account?: string; kind: 'account'; path: string; type: IdlV00Type; }; // A nested/recursive version of IdlV00Account. export type IdlV00Accounts = { accounts: IdlV00AccountItem[]; docs?: string[]; name: string; }; export type IdlV00Field = { docs?: string[]; name: string; type: IdlV00Type; }; export type IdlV00TypeDef = { docs?: string[]; name: string; type: IdlV00TypeDefTy; }; export type IdlV00AccountDef = { docs?: string[]; name: string; seeds?: IdlV00PdaSeedDef[]; size?: number; type: IdlV00TypeDefTyStruct; }; export type IdlV00PdaDef = { docs?: string[]; name: string; seeds?: IdlV00PdaSeedDef[]; }; export type IdlV00PdaSeedDef = | { description: string; kind: 'variable'; name: string; type: IdlV00Type } | { kind: 'constant'; type: IdlV00Type; value: boolean | number | string } | { kind: 'programId' }; export type IdlV00TypeDefTyStruct = { fields: Array; kind: 'struct'; }; export type IdlV00TypeDefTyEnum = { kind: 'enum'; size?: IdlV00TypeUnsignedInteger; variants: IdlV00EnumVariant[]; }; export type IdlV00TypeDefTyAlias = { kind: 'alias'; value: IdlV00Type; }; export type IdlV00TypeDefTy = IdlV00TypeDefTyAlias | IdlV00TypeDefTyEnum | IdlV00TypeDefTyStruct; export type IdlV00Type = | IdlV00TypeArray | IdlV00TypeDefined | IdlV00TypeMap | IdlV00TypeNumber | IdlV00TypeOption | IdlV00TypeSet | IdlV00TypeTuple | IdlV00TypeVec | 'bool' | 'bytes' | 'publicKey' | 'string'; export type IdlV00TypeUnsignedInteger = 'shortU16' | 'u8' | 'u16' | 'u32' | 'u64' | 'u128'; export type IdlV00TypeSignedInteger = 'i8' | 'i16' | 'i32' | 'i64' | 'i128'; export type IdlV00TypeInteger = IdlV00TypeSignedInteger | IdlV00TypeUnsignedInteger; export type IdlV00TypeDecimals = 'f32' | 'f64'; export type IdlV00TypeNumber = IdlV00TypeDecimals | IdlV00TypeInteger; // User defined type. export type IdlV00TypeDefined = { defined: string; }; export type IdlV00TypeOption = { fixed?: boolean; prefix?: IdlV00TypeUnsignedInteger; } & ({ coption: IdlV00Type } | { option: IdlV00Type }); export type IdlV00TypeVec = { size?: IdlV00TypeUnsignedInteger | 'remainder'; vec: IdlV00Type; }; export type IdlV00TypeTuple = { tuple: IdlV00Type[] }; export type IdlV00TypeArray = { array: [idlV00Type: IdlV00Type, size: number]; }; export type IdlV00TypeHashMap = { hashMap: [IdlV00Type, IdlV00Type] }; export type IdlV00TypeBTreeMap = { bTreeMap: [IdlV00Type, IdlV00Type] }; export type IdlV00TypeMap = { size?: IdlV00TypeUnsignedInteger | number | 'remainder'; } & (IdlV00TypeBTreeMap | IdlV00TypeHashMap); export type IdlV00TypeHashSet = { hashSet: IdlV00Type }; export type IdlV00TypeBTreeSet = { bTreeSet: IdlV00Type }; export type IdlV00TypeSet = { size?: IdlV00TypeUnsignedInteger | number | 'remainder'; } & (IdlV00TypeBTreeSet | IdlV00TypeHashSet); export type IdlV00EnumVariant = { fields?: IdlV00EnumFields; name: string; }; export type IdlV00EnumFields = IdlV00EnumFieldsNamed | IdlV00EnumFieldsTuple; export type IdlV00EnumFieldsNamed = IdlV00Field[]; export type IdlV00EnumFieldsTuple = IdlV00Type[]; export type IdlV00ErrorCode = { code: number; docs?: string[]; msg?: string; name: string; }; ================================================ FILE: packages/nodes-from-anchor/src/v00/index.ts ================================================ export * from './AccountNode'; export * from './DefinedTypeNode'; export * from './ErrorNode'; export * from './InstructionAccountNode'; export * from './InstructionArgumentNode'; export * from './InstructionNode'; export * from './PdaNode'; export * from './ProgramNode'; export * from './RootNode'; export * from './idl'; export * from './typeNodes'; ================================================ FILE: packages/nodes-from-anchor/src/v00/typeNodes/ArrayTypeNode.ts ================================================ import { ArrayTypeNode, arrayTypeNode, fixedCountNode, numberTypeNode, prefixedCountNode, remainderCountNode, } from '@codama/nodes'; import { IdlV00TypeArray, IdlV00TypeVec } from '../idl'; import { typeNodeFromAnchorV00 } from './TypeNode'; export function arrayTypeNodeFromAnchorV00(idl: IdlV00TypeArray | IdlV00TypeVec): ArrayTypeNode { if ('array' in idl) { const item = typeNodeFromAnchorV00(idl.array[0]); return arrayTypeNode(item, fixedCountNode(idl.array[1])); } const item = typeNodeFromAnchorV00(idl.vec); if (idl.size === 'remainder') return arrayTypeNode(item, remainderCountNode()); return arrayTypeNode(item, prefixedCountNode(numberTypeNode(idl.size ?? 'u32'))); } ================================================ FILE: packages/nodes-from-anchor/src/v00/typeNodes/EnumEmptyVariantTypeNode.ts ================================================ import { EnumEmptyVariantTypeNode, enumEmptyVariantTypeNode } from '@codama/nodes'; import { IdlV00EnumVariant } from '../idl'; export function enumEmptyVariantTypeNodeFromAnchorV00(idl: IdlV00EnumVariant): EnumEmptyVariantTypeNode { return enumEmptyVariantTypeNode(idl.name ?? ''); } ================================================ FILE: packages/nodes-from-anchor/src/v00/typeNodes/EnumStructVariantTypeNode.ts ================================================ import { EnumStructVariantTypeNode, enumStructVariantTypeNode, StructTypeNode } from '@codama/nodes'; import { IdlV00EnumFieldsNamed, IdlV00EnumVariant } from '../idl'; import { structTypeNodeFromAnchorV00 } from './StructTypeNode'; export function enumStructVariantTypeNodeFromAnchorV00( idl: IdlV00EnumVariant & { fields: IdlV00EnumFieldsNamed }, ): EnumStructVariantTypeNode { return enumStructVariantTypeNode( idl.name ?? '', structTypeNodeFromAnchorV00({ fields: idl.fields, kind: 'struct' }), ); } ================================================ FILE: packages/nodes-from-anchor/src/v00/typeNodes/EnumTupleVariantTypeNode.ts ================================================ import { EnumTupleVariantTypeNode, enumTupleVariantTypeNode, TupleTypeNode } from '@codama/nodes'; import { IdlV00EnumFieldsTuple, IdlV00EnumVariant } from '../idl'; import { tupleTypeNodeFromAnchorV00 } from './TupleTypeNode'; export function enumTupleVariantTypeNodeFromAnchorV00( idl: IdlV00EnumVariant & { fields: IdlV00EnumFieldsTuple }, ): EnumTupleVariantTypeNode { return enumTupleVariantTypeNode(idl.name ?? '', tupleTypeNodeFromAnchorV00({ tuple: idl.fields })); } ================================================ FILE: packages/nodes-from-anchor/src/v00/typeNodes/EnumTypeNode.ts ================================================ import { EnumTypeNode, enumTypeNode, EnumVariantTypeNode, NumberTypeNode, numberTypeNode } from '@codama/nodes'; import { IdlV00EnumFieldsNamed, IdlV00EnumFieldsTuple, IdlV00EnumVariant, IdlV00TypeDefTyEnum } from '../idl'; import { enumEmptyVariantTypeNodeFromAnchorV00 } from './EnumEmptyVariantTypeNode'; import { enumStructVariantTypeNodeFromAnchorV00 } from './EnumStructVariantTypeNode'; import { enumTupleVariantTypeNodeFromAnchorV00 } from './EnumTupleVariantTypeNode'; export function enumTypeNodeFromAnchorV00( idl: IdlV00TypeDefTyEnum, ): EnumTypeNode { const variants = idl.variants.map((variant): EnumVariantTypeNode => { if (!variant.fields || variant.fields.length <= 0) { return enumEmptyVariantTypeNodeFromAnchorV00(variant); } if (isStructVariant(variant)) { return enumStructVariantTypeNodeFromAnchorV00(variant); } return enumTupleVariantTypeNodeFromAnchorV00(variant as IdlV00EnumVariant & { fields: IdlV00EnumFieldsTuple }); }); return enumTypeNode(variants, { size: idl.size ? numberTypeNode(idl.size) : undefined, }); } function isStructVariant(variant: IdlV00EnumVariant): variant is IdlV00EnumVariant & { fields: IdlV00EnumFieldsNamed } { const field = variant.fields![0]; return typeof field === 'object' && 'name' in field && 'type' in field; } ================================================ FILE: packages/nodes-from-anchor/src/v00/typeNodes/MapTypeNode.ts ================================================ import { CountNode, fixedCountNode, MapTypeNode, mapTypeNode, numberTypeNode, prefixedCountNode, remainderCountNode, } from '@codama/nodes'; import { IdlV00TypeMap } from '../idl'; import { typeNodeFromAnchorV00 } from './TypeNode'; export function mapTypeNodeFromAnchorV00(idl: IdlV00TypeMap): MapTypeNode { const [key, value] = 'hashMap' in idl ? idl.hashMap : idl.bTreeMap; let size: CountNode | undefined; if (idl.size === 'remainder') { size = remainderCountNode(); } else if (typeof idl.size === 'number') { size = fixedCountNode(idl.size); } else { size = prefixedCountNode(numberTypeNode(idl.size ?? 'u32')); } return mapTypeNode(typeNodeFromAnchorV00(key), typeNodeFromAnchorV00(value), size); } ================================================ FILE: packages/nodes-from-anchor/src/v00/typeNodes/OptionTypeNode.ts ================================================ import { numberTypeNode, OptionTypeNode, optionTypeNode } from '@codama/nodes'; import { IdlV00TypeOption } from '../idl'; import { typeNodeFromAnchorV00 } from './TypeNode'; export function optionTypeNodeFromAnchorV00(idl: IdlV00TypeOption): OptionTypeNode { const item = 'option' in idl ? idl.option : idl.coption; const defaultPrefix = numberTypeNode('option' in idl ? 'u8' : 'u32'); const defaultFixed = !('option' in idl); return optionTypeNode(typeNodeFromAnchorV00(item), { fixed: idl.fixed !== undefined ? idl.fixed : defaultFixed, prefix: idl.prefix ? numberTypeNode(idl.prefix) : defaultPrefix, }); } ================================================ FILE: packages/nodes-from-anchor/src/v00/typeNodes/SetTypeNode.ts ================================================ import { fixedCountNode, numberTypeNode, prefixedCountNode, remainderCountNode, SetTypeNode, setTypeNode, } from '@codama/nodes'; import { IdlV00TypeSet } from '../idl'; import { typeNodeFromAnchorV00 } from './TypeNode'; export function setTypeNodeFromAnchorV00(idl: IdlV00TypeSet): SetTypeNode { const child = 'hashSet' in idl ? idl.hashSet : idl.bTreeSet; let size: SetTypeNode['count'] | undefined; if (idl.size === 'remainder') { size = remainderCountNode(); } else if (typeof idl.size === 'number') { size = fixedCountNode(idl.size); } else { size = prefixedCountNode(numberTypeNode(idl.size ?? 'u32')); } return setTypeNode(typeNodeFromAnchorV00(child), size); } ================================================ FILE: packages/nodes-from-anchor/src/v00/typeNodes/StructFieldTypeNode.ts ================================================ import { StructFieldTypeNode, structFieldTypeNode } from '@codama/nodes'; import { IdlV00Field } from '../idl'; import { typeNodeFromAnchorV00 } from './TypeNode'; export function structFieldTypeNodeFromAnchorV00(idl: IdlV00Field): StructFieldTypeNode { return structFieldTypeNode({ docs: idl.docs ?? [], name: idl.name ?? '', type: typeNodeFromAnchorV00(idl.type), }); } ================================================ FILE: packages/nodes-from-anchor/src/v00/typeNodes/StructTypeNode.ts ================================================ import { StructTypeNode, structTypeNode } from '@codama/nodes'; import { IdlV00TypeDefTyStruct } from '../idl'; import { structFieldTypeNodeFromAnchorV00 } from './StructFieldTypeNode'; export function structTypeNodeFromAnchorV00(idl: IdlV00TypeDefTyStruct): StructTypeNode { return structTypeNode((idl.fields ?? []).map(structFieldTypeNodeFromAnchorV00)); } ================================================ FILE: packages/nodes-from-anchor/src/v00/typeNodes/TupleTypeNode.ts ================================================ import { TupleTypeNode, tupleTypeNode } from '@codama/nodes'; import { IdlV00TypeTuple } from '../idl'; import { typeNodeFromAnchorV00 } from './TypeNode'; export function tupleTypeNodeFromAnchorV00(idl: IdlV00TypeTuple): TupleTypeNode { return tupleTypeNode(idl.tuple.map(typeNodeFromAnchorV00)); } ================================================ FILE: packages/nodes-from-anchor/src/v00/typeNodes/TypeNode.ts ================================================ import { CODAMA_ERROR__ANCHOR__UNRECOGNIZED_IDL_TYPE, CodamaError } from '@codama/errors'; import { booleanTypeNode, bytesTypeNode, definedTypeLinkNode, numberTypeNode, publicKeyTypeNode, sizePrefixTypeNode, stringTypeNode, TypeNode, } from '@codama/nodes'; import { IdlV00Type, IdlV00TypeDefTy, IdlV00TypeMap, IdlV00TypeSet } from '../idl'; import { arrayTypeNodeFromAnchorV00 } from './ArrayTypeNode'; import { enumTypeNodeFromAnchorV00 } from './EnumTypeNode'; import { mapTypeNodeFromAnchorV00 } from './MapTypeNode'; import { optionTypeNodeFromAnchorV00 } from './OptionTypeNode'; import { setTypeNodeFromAnchorV00 } from './SetTypeNode'; import { structTypeNodeFromAnchorV00 } from './StructTypeNode'; import { tupleTypeNodeFromAnchorV00 } from './TupleTypeNode'; const IDL_V00_TYPE_LEAVES = [ 'string', 'publicKey', 'bytes', 'bool', 'u8', 'u16', 'u32', 'u64', 'u128', 'i8', 'i16', 'i32', 'i64', 'i128', 'f32', 'f64', 'shortU16', ] as const; export const typeNodeFromAnchorV00 = (idlType: IdlV00Type | IdlV00TypeDefTy): TypeNode => { // Leaf. if (typeof idlType === 'string' && IDL_V00_TYPE_LEAVES.includes(idlType)) { if (idlType === 'bool') return booleanTypeNode(); if (idlType === 'publicKey') return publicKeyTypeNode(); if (idlType === 'string') return sizePrefixTypeNode(stringTypeNode('utf8'), numberTypeNode('u32')); if (idlType === 'bytes') return sizePrefixTypeNode(bytesTypeNode(), numberTypeNode('u32')); return numberTypeNode(idlType); } // Ensure eveything else is an object. if (typeof idlType !== 'object') { throw new CodamaError(CODAMA_ERROR__ANCHOR__UNRECOGNIZED_IDL_TYPE, { idlType: JSON.stringify(idlType), }); } // Array. if ('array' in idlType && isArrayOfSize(idlType.array, 2)) { return arrayTypeNodeFromAnchorV00(idlType); } // Vec. if ('vec' in idlType) { return arrayTypeNodeFromAnchorV00(idlType); } // Defined link. if ('defined' in idlType && typeof idlType.defined === 'string') { return definedTypeLinkNode(idlType.defined); } // Enum. if ('kind' in idlType && idlType.kind === 'enum' && 'variants' in idlType) { return enumTypeNodeFromAnchorV00(idlType); } // Alias. if ('kind' in idlType && idlType.kind === 'alias' && 'value' in idlType) { return typeNodeFromAnchorV00(idlType.value); } // Map. if ( ('hashMap' in idlType && isArrayOfSize(idlType.hashMap, 2)) || ('bTreeMap' in idlType && isArrayOfSize(idlType.bTreeMap, 2)) ) { return mapTypeNodeFromAnchorV00(idlType as IdlV00TypeMap); } // Option. if ('option' in idlType || 'coption' in idlType) { return optionTypeNodeFromAnchorV00(idlType); } // Set. if ('hashSet' in idlType || 'bTreeSet' in idlType) { return setTypeNodeFromAnchorV00(idlType as IdlV00TypeSet); } // Struct. if ('kind' in idlType && 'fields' in idlType && idlType.kind === 'struct') { return structTypeNodeFromAnchorV00(idlType); } // Tuple. if ('tuple' in idlType && Array.isArray(idlType.tuple)) { return tupleTypeNodeFromAnchorV00(idlType); } throw new CodamaError(CODAMA_ERROR__ANCHOR__UNRECOGNIZED_IDL_TYPE, { idlType: JSON.stringify(idlType), }); }; // eslint-disable-next-line @typescript-eslint/no-explicit-any function isArrayOfSize(array: any, size: number): boolean { return Array.isArray(array) && array.length === size; } ================================================ FILE: packages/nodes-from-anchor/src/v00/typeNodes/index.ts ================================================ export * from './ArrayTypeNode'; export * from './EnumEmptyVariantTypeNode'; export * from './EnumStructVariantTypeNode'; export * from './EnumTupleVariantTypeNode'; export * from './EnumTypeNode'; export * from './MapTypeNode'; export * from './OptionTypeNode'; export * from './SetTypeNode'; export * from './StructFieldTypeNode'; export * from './StructTypeNode'; export * from './TupleTypeNode'; export * from './TypeNode'; ================================================ FILE: packages/nodes-from-anchor/src/v01/AccountNode.ts ================================================ import { CODAMA_ERROR__ANCHOR__ACCOUNT_TYPE_MISSING, CodamaError } from '@codama/errors'; import { AccountNode, accountNode, assertIsNode, bytesTypeNode, camelCase, fieldDiscriminatorNode, fixedSizeTypeNode, structFieldTypeNode, structTypeNode, } from '@codama/nodes'; import { getAnchorDiscriminatorV01 } from './../discriminators'; import type { IdlV01Account, IdlV01TypeDef } from './idl'; import { typeNodeFromAnchorV01 } from './typeNodes'; import type { GenericsV01 } from './unwrapGenerics'; export function accountNodeFromAnchorV01( idl: IdlV01Account, types: IdlV01TypeDef[], generics: GenericsV01, ): AccountNode { const name = camelCase(idl.name); const type = types.find(({ name }) => name === idl.name); if (!type) { throw new CodamaError(CODAMA_ERROR__ANCHOR__ACCOUNT_TYPE_MISSING, { name: idl.name }); } const data = typeNodeFromAnchorV01(type.type, generics); assertIsNode(data, 'structTypeNode'); const discriminator = structFieldTypeNode({ defaultValue: getAnchorDiscriminatorV01(idl.discriminator), defaultValueStrategy: 'omitted', name: 'discriminator', type: fixedSizeTypeNode(bytesTypeNode(), idl.discriminator.length), }); return accountNode({ data: structTypeNode([discriminator, ...data.fields]), discriminators: [fieldDiscriminatorNode('discriminator')], name, }); } ================================================ FILE: packages/nodes-from-anchor/src/v01/DefinedTypeNode.ts ================================================ import { DefinedTypeNode, definedTypeNode } from '@codama/nodes'; import type { IdlV01TypeDef } from './idl'; import { typeNodeFromAnchorV01 } from './typeNodes'; import type { GenericsV01 } from './unwrapGenerics'; export function definedTypeNodeFromAnchorV01(idl: Partial, generics: GenericsV01): DefinedTypeNode { const name = idl.name ?? ''; const idlType = idl.type ?? { fields: [], kind: 'struct' }; const type = typeNodeFromAnchorV01(idlType, generics); return definedTypeNode({ docs: idl.docs, name, type }); } ================================================ FILE: packages/nodes-from-anchor/src/v01/ErrorNode.ts ================================================ import { ErrorNode, errorNode } from '@codama/nodes'; import { IdlV01ErrorCode } from './idl'; export function errorNodeFromAnchorV01(idl: Partial): ErrorNode { const name = idl.name ?? ''; const msg = idl.msg ?? ''; return errorNode({ code: idl.code ?? -1, docs: `${name}: ${msg}`, message: msg, name, }); } ================================================ FILE: packages/nodes-from-anchor/src/v01/EventNode.ts ================================================ import { CODAMA_ERROR__ANCHOR__EVENT_TYPE_MISSING, CodamaError } from '@codama/errors'; import { bytesTypeNode, camelCase, constantDiscriminatorNode, constantValueNode, EventNode, eventNode, fixedSizeTypeNode, hiddenPrefixTypeNode, } from '@codama/nodes'; import { getAnchorDiscriminatorV01 } from './../discriminators'; import type { IdlV01Event, IdlV01TypeDef } from './idl'; import { typeNodeFromAnchorV01 } from './typeNodes'; import type { GenericsV01 } from './unwrapGenerics'; export function eventNodeFromAnchorV01(idl: IdlV01Event, types: IdlV01TypeDef[], generics: GenericsV01): EventNode { const name = camelCase(idl.name); const type = types.find(candidate => candidate.name === idl.name); if (!type) { throw new CodamaError(CODAMA_ERROR__ANCHOR__EVENT_TYPE_MISSING, { name: idl.name }); } const data = typeNodeFromAnchorV01(type.type, generics); const discriminator = getAnchorDiscriminatorV01(idl.discriminator); const discriminatorConstant = constantValueNode( fixedSizeTypeNode(bytesTypeNode(), idl.discriminator.length), discriminator, ); return eventNode({ data: hiddenPrefixTypeNode(data, [discriminatorConstant]), discriminators: [constantDiscriminatorNode(discriminatorConstant)], name, }); } ================================================ FILE: packages/nodes-from-anchor/src/v01/InstructionAccountNode.ts ================================================ import { AccountValueNode, ArgumentValueNode, camelCase, InstructionAccountNode, instructionAccountNode, InstructionArgumentNode, isNode, pdaNode, PdaSeedNode, PdaSeedValueNode, PdaValueNode, pdaValueNode, PublicKeyValueNode, publicKeyValueNode, } from '@codama/nodes'; import { IdlV01InstructionAccount, IdlV01InstructionAccountItem, IdlV01Seed } from './idl'; import { pdaSeedNodeFromAnchorV01 } from './PdaSeedNode'; function hasDuplicateAccountNames(idl: IdlV01InstructionAccountItem[]): boolean { const seenNames = new Set(); function checkDuplicates(items: IdlV01InstructionAccountItem[]): boolean { for (const item of items) { if ('accounts' in item) { if (checkDuplicates(item.accounts)) { return true; } } else { const name = camelCase(item.name ?? ''); if (seenNames.has(name)) { return true; } seenNames.add(name); } } return false; } return checkDuplicates(idl); } export function instructionAccountNodesFromAnchorV01( idl: IdlV01InstructionAccountItem[], instructionArguments: InstructionArgumentNode[], prefix?: string, ): InstructionAccountNode[] { const shouldPrefix = prefix !== undefined || hasDuplicateAccountNames(idl); return idl.flatMap(account => 'accounts' in account ? instructionAccountNodesFromAnchorV01( account.accounts, instructionArguments, shouldPrefix ? (prefix ? `${prefix}_${account.name}` : account.name) : undefined, ) : [instructionAccountNodeFromAnchorV01(account, instructionArguments, shouldPrefix ? prefix : undefined)], ); } export function instructionAccountNodeFromAnchorV01( idl: IdlV01InstructionAccount, instructionArguments: InstructionArgumentNode[], prefix?: string, ): InstructionAccountNode { const isOptional = idl.optional ?? false; const docs = idl.docs ?? []; const isSigner = idl.signer ?? false; const isWritable = idl.writable ?? false; const name = prefix ? `${prefix}_${idl.name ?? ''}` : (idl.name ?? ''); let defaultValue: PdaValueNode | PublicKeyValueNode | undefined; if (idl.address) { defaultValue = publicKeyValueNode(idl.address, name); } else if (idl.pda) { // TODO: Handle seeds with nested paths. // Currently, we gracefully ignore PDA default values if we encounter seeds with nested paths. const seedsWithNestedPaths = idl.pda.seeds.some(seed => 'path' in seed && seed.path.includes('.')); if (!seedsWithNestedPaths) { const [seedDefinitions, seedValues] = idl.pda.seeds.reduce( ([seeds, lookups], seed: IdlV01Seed) => { const { definition, value } = pdaSeedNodeFromAnchorV01(seed, instructionArguments, prefix); return [[...seeds, definition], value ? [...lookups, value] : lookups]; }, <[PdaSeedNode[], PdaSeedValueNode[]]>[[], []], ); let programId: string | undefined; let programIdValue: AccountValueNode | ArgumentValueNode | undefined; if (idl.pda.program !== undefined) { const { definition, value } = pdaSeedNodeFromAnchorV01(idl.pda.program, instructionArguments, prefix); if ( isNode(definition, 'constantPdaSeedNode') && isNode(definition.value, 'bytesValueNode') && definition.value.encoding === 'base58' ) { programId = definition.value.data; } else if (value && isNode(value.value, ['accountValueNode', 'argumentValueNode'])) { programIdValue = value.value; } } defaultValue = pdaValueNode( pdaNode({ name, programId, seeds: seedDefinitions }), seedValues, programIdValue, ); } } return instructionAccountNode({ defaultValue, docs, isOptional, isSigner, isWritable, name, }); } ================================================ FILE: packages/nodes-from-anchor/src/v01/InstructionArgumentNode.ts ================================================ import { InstructionArgumentNode, instructionArgumentNode } from '@codama/nodes'; import type { IdlV01Field } from './idl'; import { typeNodeFromAnchorV01 } from './typeNodes'; import type { GenericsV01 } from './unwrapGenerics'; export function instructionArgumentNodeFromAnchorV01(idl: IdlV01Field, generics: GenericsV01): InstructionArgumentNode { return instructionArgumentNode({ docs: idl.docs ?? [], name: idl.name, type: typeNodeFromAnchorV01(idl.type, generics), }); } ================================================ FILE: packages/nodes-from-anchor/src/v01/InstructionNode.ts ================================================ import { bytesTypeNode, camelCase, fieldDiscriminatorNode, fixedSizeTypeNode, instructionArgumentNode, InstructionNode, instructionNode, } from '@codama/nodes'; import { getAnchorDiscriminatorV01 } from '../discriminators'; import type { IdlV01Instruction } from './idl'; import { instructionAccountNodesFromAnchorV01 } from './InstructionAccountNode'; import { instructionArgumentNodeFromAnchorV01 } from './InstructionArgumentNode'; import type { GenericsV01 } from './unwrapGenerics'; export function instructionNodeFromAnchorV01(idl: IdlV01Instruction, generics: GenericsV01): InstructionNode { const name = idl.name; let dataArguments = idl.args.map(arg => instructionArgumentNodeFromAnchorV01(arg, generics)); const discriminatorField = instructionArgumentNode({ defaultValue: getAnchorDiscriminatorV01(idl.discriminator), defaultValueStrategy: 'omitted', name: 'discriminator', type: fixedSizeTypeNode(bytesTypeNode(), idl.discriminator.length), }); dataArguments = [discriminatorField, ...dataArguments]; const discriminators = [fieldDiscriminatorNode('discriminator')]; return instructionNode({ accounts: instructionAccountNodesFromAnchorV01(idl.accounts ?? [], dataArguments), arguments: dataArguments, discriminators, docs: idl.docs ?? [], name: camelCase(name), optionalAccountStrategy: 'programId', }); } ================================================ FILE: packages/nodes-from-anchor/src/v01/PdaSeedNode.ts ================================================ import { CODAMA_ERROR__ANCHOR__ARGUMENT_TYPE_MISSING, CODAMA_ERROR__ANCHOR__SEED_KIND_UNIMPLEMENTED, CodamaError, } from '@codama/errors'; import { accountValueNode, argumentValueNode, camelCase, constantPdaSeedNodeFromBytes, InstructionArgumentNode, isNode, PdaSeedNode, PdaSeedValueNode, pdaSeedValueNode, publicKeyTypeNode, stringTypeNode, variablePdaSeedNode, } from '@codama/nodes'; import { getBase58Codec } from '@solana/codecs'; import { IdlV01Seed } from './idl'; export function pdaSeedNodeFromAnchorV01( seed: IdlV01Seed, instructionArguments: InstructionArgumentNode[], prefix?: string, ): Readonly<{ definition: PdaSeedNode; value?: PdaSeedValueNode }> { const kind = seed.kind; switch (kind) { case 'const': return { definition: constantPdaSeedNodeFromBytes('base58', getBase58Codec().decode(new Uint8Array(seed.value))), }; case 'account': { // Ignore nested paths. const [accountName] = seed.path.split('.'); const prefixedAccountName = prefix ? `${prefix}_${accountName}` : accountName; return { definition: variablePdaSeedNode(prefixedAccountName, publicKeyTypeNode()), value: pdaSeedValueNode(prefixedAccountName, accountValueNode(prefixedAccountName)), }; } case 'arg': { // Ignore nested paths. const [originalArgumentName] = seed.path.split('.'); const argumentName = camelCase(originalArgumentName); const argumentNode = instructionArguments.find(({ name }) => name === argumentName); if (!argumentNode) { throw new CodamaError(CODAMA_ERROR__ANCHOR__ARGUMENT_TYPE_MISSING, { name: originalArgumentName }); } // Anchor uses unprefixed strings for PDA seeds even though the // argument itself uses a Borsh size-prefixed string. Thus, we // must recognize this case and convert the type accordingly. const isBorshString = isNode(argumentNode.type, 'sizePrefixTypeNode') && isNode(argumentNode.type.type, 'stringTypeNode') && argumentNode.type.type.encoding === 'utf8' && isNode(argumentNode.type.prefix, 'numberTypeNode') && argumentNode.type.prefix.format === 'u32'; const argumentType = isBorshString ? stringTypeNode('utf8') : argumentNode.type; return { definition: variablePdaSeedNode(argumentNode.name, argumentType), value: pdaSeedValueNode(argumentNode.name, argumentValueNode(argumentNode.name)), }; } default: throw new CodamaError(CODAMA_ERROR__ANCHOR__SEED_KIND_UNIMPLEMENTED, { kind }); } } ================================================ FILE: packages/nodes-from-anchor/src/v01/ProgramNode.ts ================================================ import { ProgramNode, programNode, ProgramVersion } from '@codama/nodes'; import { accountNodeFromAnchorV01 } from './AccountNode'; import { definedTypeNodeFromAnchorV01 } from './DefinedTypeNode'; import { errorNodeFromAnchorV01 } from './ErrorNode'; import { eventNodeFromAnchorV01 } from './EventNode'; import { IdlV01 } from './idl'; import { instructionNodeFromAnchorV01 } from './InstructionNode'; import { extractGenerics } from './unwrapGenerics'; export function programNodeFromAnchorV01(idl: IdlV01): ProgramNode { const [types, generics] = extractGenerics(idl.types ?? []); const accounts = idl.accounts ?? []; const events = idl.events ?? []; const instructions = idl.instructions ?? []; const errors = idl.errors ?? []; const filteredTypes = types.filter( type => !accounts.some(account => account.name === type.name) && !events.some(event => event.name === type.name), ); const definedTypes = filteredTypes.map(type => definedTypeNodeFromAnchorV01(type, generics)); const accountNodes = accounts.map(account => accountNodeFromAnchorV01(account, types, generics)); return programNode({ accounts: accountNodes, definedTypes, errors: errors.map(errorNodeFromAnchorV01), events: events.map(event => eventNodeFromAnchorV01(event, types, generics)), instructions: instructions.map(instruction => instructionNodeFromAnchorV01(instruction, generics)), name: idl.metadata.name, origin: 'anchor', publicKey: idl.address, version: idl.metadata.version as ProgramVersion, }); } ================================================ FILE: packages/nodes-from-anchor/src/v01/RootNode.ts ================================================ import { RootNode, rootNode } from '@codama/nodes'; import { IdlV01 } from './idl'; import { programNodeFromAnchorV01 } from './ProgramNode'; export function rootNodeFromAnchorV01(program: IdlV01, additionalPrograms: IdlV01[] = []): RootNode { const programNode = programNodeFromAnchorV01(program); const additionalProgramNodes = additionalPrograms.map(programNodeFromAnchorV01); return rootNode(programNode, additionalProgramNodes); } ================================================ FILE: packages/nodes-from-anchor/src/v01/idl.ts ================================================ export type IdlV01 = { accounts?: IdlV01Account[]; address: string; constants?: IdlV01Const[]; docs?: string[]; errors?: IdlV01ErrorCode[]; events?: IdlV01Event[]; instructions: IdlV01Instruction[]; metadata: IdlV01Metadata; types?: IdlV01TypeDef[]; }; export type IdlV01Metadata = { contact?: string; dependencies?: IdlV01Dependency[]; deployments?: IdlV01Deployments; description?: string; name: string; repository?: string; spec: string; version: string; }; export type IdlV01Dependency = { name: string; version: string; }; export type IdlV01Deployments = { devnet?: string; localnet?: string; mainnet?: string; testnet?: string; }; export type IdlV01Instruction = { accounts: IdlV01InstructionAccountItem[]; args: IdlV01Field[]; discriminator: IdlV01Discriminator; docs?: string[]; name: string; returns?: IdlV01Type; }; export type IdlV01InstructionAccountItem = IdlV01InstructionAccount | IdlV01InstructionAccounts; export type IdlV01InstructionAccount = { address?: string; docs?: string[]; name: string; optional?: boolean; pda?: IdlV01Pda; relations?: string[]; signer?: boolean; writable?: boolean; }; export type IdlV01InstructionAccounts = { accounts: IdlV01InstructionAccount[]; name: string; }; export type IdlV01Pda = { program?: IdlV01Seed; seeds: IdlV01Seed[]; }; export type IdlV01Seed = IdlV01SeedAccount | IdlV01SeedArg | IdlV01SeedConst; export type IdlV01SeedConst = { kind: 'const'; value: number[]; }; export type IdlV01SeedArg = { kind: 'arg'; path: string; }; export type IdlV01SeedAccount = { account?: string; kind: 'account'; path: string; }; export type IdlV01Account = { discriminator: IdlV01Discriminator; name: string; }; export type IdlV01Event = { discriminator: IdlV01Discriminator; name: string; }; export type IdlV01Const = { name: string; type: IdlV01Type; value: string; }; export type IdlV01ErrorCode = { code: number; msg?: string; name: string; }; export type IdlV01Field = { docs?: string[]; name: string; type: IdlV01Type; }; export type IdlV01TypeDef = { docs?: string[]; generics?: IdlV01TypeDefGeneric[]; name: string; repr?: IdlV01Repr; serialization?: IdlV01Serialization; type: IdlV01TypeDefTy; }; export type IdlV01Serialization = 'borsh' | 'bytemuck' | 'bytemuckunsafe' | { custom: string }; export type IdlV01Repr = IdlV01ReprC | IdlV01ReprRust | IdlV01ReprTransparent; export type IdlV01ReprRust = IdlV01ReprModifier & { kind: 'rust'; }; export type IdlV01ReprC = IdlV01ReprModifier & { kind: 'c'; }; export type IdlV01ReprTransparent = { kind: 'transparent'; }; export type IdlV01ReprModifier = { align?: number; packed?: boolean; }; export type IdlV01TypeDefGeneric = IdlV01TypeDefGenericConst | IdlV01TypeDefGenericType; export type IdlV01TypeDefGenericType = { kind: 'type'; name: string; }; export type IdlV01TypeDefGenericConst = { kind: 'const'; name: string; type: string; }; export type IdlV01TypeDefTy = IdlV01TypeDefTyAlias | IdlV01TypeDefTyEnum | IdlV01TypeDefTyStruct | IdlV01TypeDefTyType; export type IdlV01TypeDefTyStruct = { fields?: IdlV01DefinedFields; kind: 'struct'; }; export type IdlV01TypeDefTyEnum = { kind: 'enum'; variants: IdlV01EnumVariant[]; }; export type IdlV01TypeDefTyAlias = { kind: 'alias'; value: IdlV01Type; }; export type IdlV01TypeDefTyType = { alias: IdlV01Type; kind: 'type'; }; export type IdlV01EnumVariant = { fields?: IdlV01DefinedFields; name: string; }; export type IdlV01DefinedFields = IdlV01DefinedFieldsNamed | IdlV01DefinedFieldsTuple; export type IdlV01DefinedFieldsNamed = IdlV01Field[]; export type IdlV01DefinedFieldsTuple = IdlV01Type[]; export type IdlV01ArrayLen = IdlV01ArrayLenGeneric | IdlV01ArrayLenValue; export type IdlV01ArrayLenGeneric = { generic: string; }; export type IdlV01ArrayLenValue = number; export type IdlV01GenericArg = IdlV01GenericArgConst | IdlV01GenericArgType; export type IdlV01GenericArgType = { kind: 'type'; type: IdlV01Type }; export type IdlV01GenericArgConst = { kind: 'const'; value: string }; export type IdlV01Type = | IdlV01TypeArray | IdlV01TypeCOption | IdlV01TypeDefined | IdlV01TypeGeneric | IdlV01TypeNumber | IdlV01TypeOption | IdlV01TypeVec | 'bool' | 'bytes' | 'pubkey' | 'string'; export type IdlV01TypeUnsignedInteger = 'shortU16' | 'u8' | 'u16' | 'u32' | 'u64' | 'u128'; export type IdlV01TypeSignedInteger = 'i8' | 'i16' | 'i32' | 'i64' | 'i128'; export type IdlV01TypeInteger = IdlV01TypeSignedInteger | IdlV01TypeUnsignedInteger; export type IdlV01TypeDecimals = 'f32' | 'f64'; export type IdlV01TypeNumber = IdlV01TypeDecimals | IdlV01TypeInteger; export type IdlV01TypeOption = { option: IdlV01Type; }; export type IdlV01TypeCOption = { coption: IdlV01Type; }; export type IdlV01TypeVec = { vec: IdlV01Type; }; export type IdlV01TypeArray = { array: [IdlV01Type: IdlV01Type, size: IdlV01ArrayLen]; }; export type IdlV01TypeDefined = { defined: { generics?: IdlV01GenericArg[]; name: string; }; }; export type IdlV01TypeGeneric = { generic: string; }; export type IdlV01Discriminator = number[]; ================================================ FILE: packages/nodes-from-anchor/src/v01/index.ts ================================================ export * from './AccountNode'; export * from './DefinedTypeNode'; export * from './EventNode'; export * from './ErrorNode'; export * from './idl'; export * from './InstructionAccountNode'; export * from './InstructionArgumentNode'; export * from './InstructionNode'; export * from './PdaSeedNode'; export * from './ProgramNode'; export * from './RootNode'; export * from './typeNodes'; export * from './unwrapGenerics'; ================================================ FILE: packages/nodes-from-anchor/src/v01/typeNodes/ArrayTypeNode.ts ================================================ import { ArrayTypeNode, arrayTypeNode, fixedCountNode, numberTypeNode, prefixedCountNode } from '@codama/nodes'; import type { IdlV01TypeArray, IdlV01TypeVec } from '../idl'; import type { GenericsV01 } from '../unwrapGenerics'; import { typeNodeFromAnchorV01 } from './TypeNode'; export function arrayTypeNodeFromAnchorV01(idl: IdlV01TypeArray | IdlV01TypeVec, generics: GenericsV01): ArrayTypeNode { if ('array' in idl) { const item = typeNodeFromAnchorV01(idl.array[0], generics); const size = typeof idl.array[1] === 'number' ? idl.array[1] : parseInt(generics.constArgs[idl.array[1].generic].value); return arrayTypeNode(item, fixedCountNode(size)); } const item = typeNodeFromAnchorV01(idl.vec, generics); return arrayTypeNode(item, prefixedCountNode(numberTypeNode('u32'))); } ================================================ FILE: packages/nodes-from-anchor/src/v01/typeNodes/EnumEmptyVariantTypeNode.ts ================================================ import { EnumEmptyVariantTypeNode, enumEmptyVariantTypeNode } from '@codama/nodes'; import { IdlV01EnumVariant } from '../idl'; export function enumEmptyVariantTypeNodeFromAnchorV01(idl: IdlV01EnumVariant): EnumEmptyVariantTypeNode { return enumEmptyVariantTypeNode(idl.name ?? ''); } ================================================ FILE: packages/nodes-from-anchor/src/v01/typeNodes/EnumStructVariantTypeNode.ts ================================================ import { EnumStructVariantTypeNode, enumStructVariantTypeNode, StructTypeNode } from '@codama/nodes'; import type { IdlV01DefinedFieldsNamed, IdlV01EnumVariant } from '../idl'; import type { GenericsV01 } from '../unwrapGenerics'; import { structTypeNodeFromAnchorV01 } from './StructTypeNode'; export function enumStructVariantTypeNodeFromAnchorV01( idl: IdlV01EnumVariant & { fields: IdlV01DefinedFieldsNamed }, generics: GenericsV01, ): EnumStructVariantTypeNode { return enumStructVariantTypeNode( idl.name ?? '', structTypeNodeFromAnchorV01({ fields: idl.fields, kind: 'struct' }, generics), ); } ================================================ FILE: packages/nodes-from-anchor/src/v01/typeNodes/EnumTupleVariantTypeNode.ts ================================================ import { EnumTupleVariantTypeNode, enumTupleVariantTypeNode, TupleTypeNode } from '@codama/nodes'; import type { IdlV01DefinedFieldsTuple, IdlV01EnumVariant } from '../idl'; import type { GenericsV01 } from '../unwrapGenerics'; import { tupleTypeNodeFromAnchorV01 } from './TupleTypeNode'; export function enumTupleVariantTypeNodeFromAnchorV01( idl: IdlV01EnumVariant & { fields: IdlV01DefinedFieldsTuple }, generics: GenericsV01, ): EnumTupleVariantTypeNode { return enumTupleVariantTypeNode(idl.name ?? '', tupleTypeNodeFromAnchorV01(idl.fields, generics)); } ================================================ FILE: packages/nodes-from-anchor/src/v01/typeNodes/EnumTypeNode.ts ================================================ import { EnumTypeNode, enumTypeNode, EnumVariantTypeNode, NumberTypeNode } from '@codama/nodes'; import type { IdlV01DefinedFieldsNamed, IdlV01DefinedFieldsTuple, IdlV01EnumVariant, IdlV01TypeDefTyEnum, } from '../idl'; import type { GenericsV01 } from '../unwrapGenerics'; import { enumEmptyVariantTypeNodeFromAnchorV01 } from './EnumEmptyVariantTypeNode'; import { enumStructVariantTypeNodeFromAnchorV01 } from './EnumStructVariantTypeNode'; import { enumTupleVariantTypeNodeFromAnchorV01 } from './EnumTupleVariantTypeNode'; export function enumTypeNodeFromAnchorV01( idl: IdlV01TypeDefTyEnum, generics: GenericsV01, ): EnumTypeNode { const variants = idl.variants.map((variant): EnumVariantTypeNode => { if (!variant.fields || variant.fields.length <= 0) { return enumEmptyVariantTypeNodeFromAnchorV01(variant); } if (isStructVariant(variant)) { return enumStructVariantTypeNodeFromAnchorV01(variant, generics); } return enumTupleVariantTypeNodeFromAnchorV01( variant as IdlV01EnumVariant & { fields: IdlV01DefinedFieldsTuple }, generics, ); }); return enumTypeNode(variants); } function isStructVariant( variant: IdlV01EnumVariant, ): variant is IdlV01EnumVariant & { fields: IdlV01DefinedFieldsNamed } { const field = variant.fields![0]; return typeof field === 'object' && 'name' in field && 'type' in field; } ================================================ FILE: packages/nodes-from-anchor/src/v01/typeNodes/OptionTypeNode.ts ================================================ import { numberTypeNode, OptionTypeNode, optionTypeNode } from '@codama/nodes'; import type { IdlV01TypeCOption, IdlV01TypeOption } from '../idl'; import type { GenericsV01 } from '../unwrapGenerics'; import { typeNodeFromAnchorV01 } from './TypeNode'; export function optionTypeNodeFromAnchorV01( idl: IdlV01TypeCOption | IdlV01TypeOption, generics: GenericsV01, ): OptionTypeNode { const item = 'option' in idl ? idl.option : idl.coption; const hasOptionField = 'option' in idl; const prefix = numberTypeNode(hasOptionField ? 'u8' : 'u32'); const fixed = !hasOptionField; return optionTypeNode(typeNodeFromAnchorV01(item, generics), { fixed, prefix, }); } ================================================ FILE: packages/nodes-from-anchor/src/v01/typeNodes/StructFieldTypeNode.ts ================================================ import { CODAMA_ERROR__ANCHOR__UNRECOGNIZED_IDL_TYPE, CodamaError } from '@codama/errors'; import { StructFieldTypeNode, structFieldTypeNode } from '@codama/nodes'; import type { IdlV01Field, IdlV01Type } from '../idl'; import type { GenericsV01 } from '../unwrapGenerics'; import { typeNodeFromAnchorV01 } from './TypeNode'; export function structFieldTypeNodeFromAnchorV01( idl: IdlV01Field | IdlV01Type, generics: GenericsV01, ): StructFieldTypeNode { if (!isStructField(idl)) { throw new CodamaError(CODAMA_ERROR__ANCHOR__UNRECOGNIZED_IDL_TYPE, { idlType: JSON.stringify(idl), }); } return structFieldTypeNode({ docs: idl.docs ?? [], name: idl.name, type: typeNodeFromAnchorV01(idl.type, generics), }); } function isStructField(field: IdlV01Field | IdlV01Type): field is IdlV01Field { return typeof field === 'object' && 'name' in field && 'type' in field; } ================================================ FILE: packages/nodes-from-anchor/src/v01/typeNodes/StructTypeNode.ts ================================================ import { StructTypeNode, structTypeNode } from '@codama/nodes'; import type { IdlV01DefinedFields, IdlV01TypeDefTyStruct } from '../idl'; import type { GenericsV01 } from '../unwrapGenerics'; import { structFieldTypeNodeFromAnchorV01 } from './StructFieldTypeNode'; export function structTypeNodeFromAnchorV01(idl: IdlV01TypeDefTyStruct, generics: GenericsV01): StructTypeNode { const fields: IdlV01DefinedFields = idl.fields ?? []; return structTypeNode(fields.map(field => structFieldTypeNodeFromAnchorV01(field, generics))); } ================================================ FILE: packages/nodes-from-anchor/src/v01/typeNodes/TupleTypeNode.ts ================================================ import { TupleTypeNode, tupleTypeNode } from '@codama/nodes'; import type { IdlV01DefinedFieldsTuple } from '../idl'; import type { GenericsV01 } from '../unwrapGenerics'; import { typeNodeFromAnchorV01 } from './TypeNode'; export function tupleTypeNodeFromAnchorV01(idl: IdlV01DefinedFieldsTuple, generics: GenericsV01): TupleTypeNode { return tupleTypeNode(idl.map(type => typeNodeFromAnchorV01(type, generics))); } ================================================ FILE: packages/nodes-from-anchor/src/v01/typeNodes/TypeNode.ts ================================================ import { CODAMA_ERROR__ANCHOR__UNRECOGNIZED_IDL_TYPE, CodamaError } from '@codama/errors'; import { booleanTypeNode, bytesTypeNode, definedTypeLinkNode, numberTypeNode, publicKeyTypeNode, sizePrefixTypeNode, stringTypeNode, TypeNode, } from '@codama/nodes'; import type { IdlV01DefinedFields, IdlV01DefinedFieldsNamed, IdlV01DefinedFieldsTuple, IdlV01Field, IdlV01Type, IdlV01TypeDefTy, } from '../idl'; import { type GenericsV01, unwrapGenericTypeFromAnchorV01 } from '../unwrapGenerics'; import { arrayTypeNodeFromAnchorV01 } from './ArrayTypeNode'; import { enumTypeNodeFromAnchorV01 } from './EnumTypeNode'; import { optionTypeNodeFromAnchorV01 } from './OptionTypeNode'; import { structTypeNodeFromAnchorV01 } from './StructTypeNode'; import { tupleTypeNodeFromAnchorV01 } from './TupleTypeNode'; const IDL_V01_TYPE_LEAVES = [ 'string', 'pubkey', 'bytes', 'bool', 'u8', 'u16', 'u32', 'u64', 'u128', 'i8', 'i16', 'i32', 'i64', 'i128', 'f32', 'f64', 'shortU16', ] as const; export const typeNodeFromAnchorV01 = (idlType: IdlV01Type | IdlV01TypeDefTy, generics: GenericsV01): TypeNode => { // Leaf. if (typeof idlType === 'string' && IDL_V01_TYPE_LEAVES.includes(idlType)) { if (idlType === 'bool') return booleanTypeNode(); if (idlType === 'pubkey') return publicKeyTypeNode(); if (idlType === 'string') return sizePrefixTypeNode(stringTypeNode('utf8'), numberTypeNode('u32')); if (idlType === 'bytes') return sizePrefixTypeNode(bytesTypeNode(), numberTypeNode('u32')); return numberTypeNode(idlType); } // Ensure eveything else is an object. if (typeof idlType !== 'object') { throw new CodamaError(CODAMA_ERROR__ANCHOR__UNRECOGNIZED_IDL_TYPE, { idlType: JSON.stringify(idlType), }); } // Array. if ('array' in idlType && isArrayOfSize(idlType.array, 2)) { return arrayTypeNodeFromAnchorV01(idlType, generics); } // Vec. if ('vec' in idlType) { return arrayTypeNodeFromAnchorV01(idlType, generics); } // Defined link. if ('defined' in idlType && typeof idlType.defined === 'object') { return 'generics' in idlType.defined ? unwrapGenericTypeFromAnchorV01(idlType, generics) : definedTypeLinkNode(idlType.defined.name); } // Generic reference. if ('generic' in idlType) { return typeNodeFromAnchorV01(generics.typeArgs[idlType.generic].type, generics); } // Enum. if ('kind' in idlType && idlType.kind === 'enum' && 'variants' in idlType) { return enumTypeNodeFromAnchorV01(idlType, generics); } // Alias. if ('kind' in idlType && idlType.kind === 'alias' && 'value' in idlType) { return typeNodeFromAnchorV01(idlType.value, generics); } // Option. if ('option' in idlType) { return optionTypeNodeFromAnchorV01(idlType, generics); } if ('coption' in idlType) { return optionTypeNodeFromAnchorV01(idlType, generics); } // Struct and Tuple. if ('kind' in idlType && idlType.kind === 'struct') { const fields = idlType.fields ?? []; if (isStructFieldArray(fields)) { return structTypeNodeFromAnchorV01(idlType, generics); } if (isTupleFieldArray(fields)) { return tupleTypeNodeFromAnchorV01(fields, generics); } } throw new CodamaError(CODAMA_ERROR__ANCHOR__UNRECOGNIZED_IDL_TYPE, { idlType: JSON.stringify(idlType), }); }; // eslint-disable-next-line @typescript-eslint/no-explicit-any function isArrayOfSize(array: any, size: number): boolean { return Array.isArray(array) && array.length === size; } function isStructFieldArray(field: IdlV01DefinedFields): field is IdlV01DefinedFieldsNamed { return field.every(isStructField); } function isTupleFieldArray(field: IdlV01DefinedFields): field is IdlV01DefinedFieldsTuple { return field.every(f => !isStructField(f)); } function isStructField(field: IdlV01Field | IdlV01Type): field is IdlV01Field { return typeof field === 'object' && 'name' in field && 'type' in field; } ================================================ FILE: packages/nodes-from-anchor/src/v01/typeNodes/index.ts ================================================ export * from './ArrayTypeNode'; export * from './EnumEmptyVariantTypeNode'; export * from './EnumStructVariantTypeNode'; export * from './EnumTupleVariantTypeNode'; export * from './EnumTypeNode'; export * from './OptionTypeNode'; export * from './StructFieldTypeNode'; export * from './StructTypeNode'; export * from './TupleTypeNode'; export * from './TypeNode'; ================================================ FILE: packages/nodes-from-anchor/src/v01/unwrapGenerics.ts ================================================ import { CODAMA_ERROR__ANCHOR__GENERIC_TYPE_MISSING, CodamaError } from '@codama/errors'; import { TypeNode } from '@codama/nodes'; import { IdlV01GenericArgConst, IdlV01GenericArgType, IdlV01TypeDef, IdlV01TypeDefGenericConst, IdlV01TypeDefGenericType, IdlV01TypeDefined, } from './idl'; import { typeNodeFromAnchorV01 } from './typeNodes'; export type GenericsV01 = { constArgs: Record; typeArgs: Record; types: Record>>; }; export function extractGenerics(types: IdlV01TypeDef[]): [IdlV01TypeDef[], GenericsV01] { const [nonGenericTypes, genericTypes] = types.reduce( (acc, type) => { acc['generics' in type ? 1 : 0].push(type); return acc; }, [[], []] as [IdlV01TypeDef[], IdlV01TypeDef[]], ); const generics = { constArgs: {}, typeArgs: {}, types: Object.fromEntries(genericTypes.map(type => [type.name, type])), } as GenericsV01; return [nonGenericTypes, generics]; } export function unwrapGenericTypeFromAnchorV01(type: IdlV01TypeDefined, generics: GenericsV01): TypeNode { const genericType = generics.types[type.defined.name]; if (!genericType) { throw new CodamaError(CODAMA_ERROR__ANCHOR__GENERIC_TYPE_MISSING, { name: type.defined.name }); } const constArgs: GenericsV01['constArgs'] = {}; const typeArgs: GenericsV01['typeArgs'] = {}; const genericDefinitions = genericType.generics ?? []; const genericArgs = type.defined.generics ?? []; genericDefinitions.forEach((genericDefinition, index) => { const genericArg = genericArgs[index]; if (genericDefinition.kind === 'const') { constArgs[genericDefinition.name] = genericArg as IdlV01GenericArgConst & IdlV01TypeDefGenericConst; } else { typeArgs[genericDefinition.name] = genericArg as IdlV01GenericArgType & IdlV01TypeDefGenericType; } }); return typeNodeFromAnchorV01(genericType.type, { ...generics, constArgs: { ...generics.constArgs, ...constArgs }, typeArgs: { ...generics.typeArgs, ...typeArgs }, }); } ================================================ FILE: packages/nodes-from-anchor/test/discriminator.test.ts ================================================ import { bytesValueNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { getAnchorAccountDiscriminatorV00, getAnchorInstructionDiscriminatorV00 } from '../src/index.js'; test('it can compute the discriminator of an Anchor account', () => { // Given an account named "StakeEntry" on the IDL. const idlName = 'StakeEntry'; // When we compute its Anchor discriminator. const discriminator = getAnchorAccountDiscriminatorV00(idlName); // Then we get the expected value. expect(discriminator).toEqual(bytesValueNode('base16', 'bb7f09239b445628')); }); test('it can compute the discriminator of an Anchor instruction', () => { // Given an instruction named "addConfigLines" on the IDL. const idlName = 'addConfigLines'; // When we compute its Anchor discriminator. const discriminator = getAnchorInstructionDiscriminatorV00(idlName); // Then we get the expected value. expect(discriminator).toEqual(bytesValueNode('base16', 'df32e0e39708736a')); }); ================================================ FILE: packages/nodes-from-anchor/test/rootNodeFromAnchor.test.ts ================================================ import { programNode, rootNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { rootNodeFromAnchor } from '../src'; test('it creates root nodes from IDL version 0.0', () => { const node = rootNodeFromAnchor({ instructions: [], metadata: { address: '1111' }, name: 'myProgram', version: '1.2.3', }); expect(node).toEqual( rootNode( programNode({ name: 'myProgram', origin: 'anchor', publicKey: '1111', version: '1.2.3', }), ), ); }); ================================================ FILE: packages/nodes-from-anchor/test/v00/AccountNode.test.ts ================================================ import { accountNode, bytesTypeNode, bytesValueNode, fieldDiscriminatorNode, fixedSizeTypeNode, numberTypeNode, structFieldTypeNode, structTypeNode, } from '@codama/nodes'; import { expect, test } from 'vitest'; import { accountNodeFromAnchorV00 } from '../../src'; test('it creates account nodes', () => { const node = accountNodeFromAnchorV00({ name: 'myAccount', type: { fields: [{ name: 'myField', type: 'u64' }], kind: 'struct', }, }); expect(node).toEqual( accountNode({ data: structTypeNode([ structFieldTypeNode({ name: 'myField', type: numberTypeNode('u64'), }), ]), name: 'myAccount', }), ); }); test('it creates account nodes with anchor discriminators', () => { const node = accountNodeFromAnchorV00( { name: 'myAccount', type: { fields: [], kind: 'struct' }, }, 'anchor', ); expect(node).toEqual( accountNode({ data: structTypeNode([ structFieldTypeNode({ defaultValue: bytesValueNode('base16', 'f61c0657fb2d322a'), defaultValueStrategy: 'omitted', name: 'discriminator', type: fixedSizeTypeNode(bytesTypeNode(), 8), }), ]), discriminators: [fieldDiscriminatorNode('discriminator')], name: 'myAccount', }), ); }); ================================================ FILE: packages/nodes-from-anchor/test/v00/DefinedTypeNode.test.ts ================================================ import { definedTypeNode, numberTypeNode, structFieldTypeNode, structTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { definedTypeNodeFromAnchorV00 } from '../../src'; test('it creates defined type nodes', () => { const node = definedTypeNodeFromAnchorV00({ name: 'myType', type: { fields: [{ name: 'myField', type: 'u64' }], kind: 'struct', }, }); expect(node).toEqual( definedTypeNode({ name: 'myType', type: structTypeNode([ structFieldTypeNode({ name: 'myField', type: numberTypeNode('u64'), }), ]), }), ); }); ================================================ FILE: packages/nodes-from-anchor/test/v00/ErrorNode.test.ts ================================================ import { errorNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { errorNodeFromAnchorV00 } from '../../src'; test('it creates error nodes', () => { const node = errorNodeFromAnchorV00({ code: 42, msg: 'my error message', name: 'myError', }); expect(node).toEqual( errorNode({ code: 42, docs: ['myError: my error message'], message: 'my error message', name: 'myError', }), ); }); ================================================ FILE: packages/nodes-from-anchor/test/v00/InstructionAccountNode.test.ts ================================================ import { instructionAccountNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { instructionAccountNodeFromAnchorV00, instructionAccountNodesFromAnchorV00 } from '../../src'; test('it creates instruction account nodes', () => { const node = instructionAccountNodeFromAnchorV00({ docs: ['my docs'], isMut: true, isOptional: true, isSigner: false, name: 'myInstructionAccount', }); expect(node).toEqual( instructionAccountNode({ docs: ['my docs'], isOptional: true, isSigner: false, isWritable: true, name: 'myInstructionAccount', }), ); }); test('it flattens nested instruction accounts without prefixing when no duplicates exist', () => { const nodes = instructionAccountNodesFromAnchorV00([ { isMut: false, isSigner: false, name: 'accountA' }, { accounts: [ { isMut: true, isSigner: false, name: 'accountB' }, { isMut: false, isSigner: true, name: 'accountC' }, ], name: 'nested', }, { isMut: true, isSigner: true, name: 'accountD' }, ]); expect(nodes).toEqual([ instructionAccountNode({ isSigner: false, isWritable: false, name: 'accountA' }), instructionAccountNode({ isSigner: false, isWritable: true, name: 'accountB' }), instructionAccountNode({ isSigner: true, isWritable: false, name: 'accountC' }), instructionAccountNode({ isSigner: true, isWritable: true, name: 'accountD' }), ]); }); test('it prevents duplicate names by prefixing nested accounts with different parent names', () => { const nodes = instructionAccountNodesFromAnchorV00([ { accounts: [ { isMut: false, isSigner: false, name: 'mint' }, { isMut: false, isSigner: true, name: 'authority' }, ], name: 'tokenProgram', }, { accounts: [ { isMut: true, isSigner: false, name: 'mint' }, { isMut: true, isSigner: false, name: 'metadata' }, ], name: 'nftProgram', }, ]); expect(nodes).toEqual([ instructionAccountNode({ isSigner: false, isWritable: false, name: 'tokenProgramMint' }), instructionAccountNode({ isSigner: true, isWritable: false, name: 'tokenProgramAuthority' }), instructionAccountNode({ isSigner: false, isWritable: true, name: 'nftProgramMint' }), instructionAccountNode({ isSigner: false, isWritable: true, name: 'nftProgramMetadata' }), ]); }); ================================================ FILE: packages/nodes-from-anchor/test/v00/InstructionArgumentNode.test.ts ================================================ import { instructionArgumentNode, numberTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { instructionArgumentNodeFromAnchorV00 } from '../../src'; test('it creates instruction argument nodes', () => { const node = instructionArgumentNodeFromAnchorV00({ name: 'myInstructionArgument', type: 'u8', }); expect(node).toEqual( instructionArgumentNode({ name: 'myInstructionArgument', type: numberTypeNode('u8'), }), ); }); ================================================ FILE: packages/nodes-from-anchor/test/v00/InstructionNode.test.ts ================================================ import { bytesTypeNode, bytesValueNode, fieldDiscriminatorNode, fixedSizeTypeNode, instructionAccountNode, instructionArgumentNode, instructionNode, numberTypeNode, } from '@codama/nodes'; import { expect, test } from 'vitest'; import { instructionNodeFromAnchorV00 } from '../../src'; test('it creates instruction nodes', () => { const node = instructionNodeFromAnchorV00( { accounts: [{ isMut: true, isSigner: false, name: 'mint' }], args: [{ name: 'amount', type: 'u8' }], name: 'mintTokens', }, 0, ); expect(node).toEqual( instructionNode({ accounts: [instructionAccountNode({ isSigner: false, isWritable: true, name: 'mint' })], arguments: [instructionArgumentNode({ name: 'amount', type: numberTypeNode('u8') })], name: 'mintTokens', }), ); }); test('it creates instruction nodes with anchor discriminators', () => { const node = instructionNodeFromAnchorV00( { accounts: [], args: [], name: 'myInstruction', }, 0, 'anchor', ); expect(node).toEqual( instructionNode({ arguments: [ instructionArgumentNode({ defaultValue: bytesValueNode('base16', 'c3f1b80e7f9b4435'), defaultValueStrategy: 'omitted', name: 'discriminator', type: fixedSizeTypeNode(bytesTypeNode(), 8), }), ], discriminators: [fieldDiscriminatorNode('discriminator')], name: 'myInstruction', }), ); }); ================================================ FILE: packages/nodes-from-anchor/test/v00/PdaNode.test.ts ================================================ import { constantPdaSeedNode, constantPdaSeedNodeFromProgramId, numberTypeNode, numberValueNode, pdaNode, variablePdaSeedNode, } from '@codama/nodes'; import { expect, test } from 'vitest'; import { pdaNodeFromAnchorV00 } from '../../src'; test('it creates PDA nodes', () => { const node = pdaNodeFromAnchorV00({ name: 'myPda', seeds: [ { kind: 'programId' }, { kind: 'constant', type: 'u8', value: 42 }, { description: 'seed description', kind: 'variable', name: 'myVariableSeed', type: 'u16' }, ], }); expect(node).toEqual( pdaNode({ name: 'myPda', seeds: [ constantPdaSeedNodeFromProgramId(), constantPdaSeedNode(numberTypeNode('u8'), numberValueNode(42)), variablePdaSeedNode('myVariableSeed', numberTypeNode('u16'), 'seed description'), ], }), ); }); ================================================ FILE: packages/nodes-from-anchor/test/v00/ProgramNode.test.ts ================================================ import { accountNode, bytesTypeNode, bytesValueNode, constantPdaSeedNodeFromProgramId, definedTypeNode, errorNode, fieldDiscriminatorNode, fixedSizeTypeNode, instructionArgumentNode, instructionNode, pdaLinkNode, pdaNode, programNode, structTypeNode, } from '@codama/nodes'; import { expect, test } from 'vitest'; import { programNodeFromAnchorV00 } from '../../src'; test('it creates program nodes', () => { const node = programNodeFromAnchorV00({ accounts: [{ name: 'myAccount', seeds: [{ kind: 'programId' }], type: { fields: [], kind: 'struct' } }], errors: [{ code: 42, msg: 'my error message', name: 'myError' }], instructions: [{ accounts: [], args: [], name: 'myInstruction' }], metadata: { address: '1111', origin: 'shank' }, name: 'myProgram', types: [{ name: 'myType', type: { fields: [], kind: 'struct' } }], version: '1.2.3', }); expect(node).toEqual( programNode({ accounts: [accountNode({ name: 'myAccount', pda: pdaLinkNode('myAccount') })], definedTypes: [definedTypeNode({ name: 'myType', type: structTypeNode([]) })], errors: [ errorNode({ code: 42, docs: ['myError: my error message'], message: 'my error message', name: 'myError', }), ], instructions: [ instructionNode({ arguments: [ instructionArgumentNode({ defaultValue: bytesValueNode('base16', (0).toString(16)), defaultValueStrategy: 'omitted', name: 'discriminator', type: fixedSizeTypeNode(bytesTypeNode(), 1), }), ], discriminators: [fieldDiscriminatorNode('discriminator')], name: 'myInstruction', }), ], name: 'myProgram', origin: 'shank', pdas: [pdaNode({ name: 'myAccount', seeds: [constantPdaSeedNodeFromProgramId()] })], publicKey: '1111', version: '1.2.3', }), ); }); ================================================ FILE: packages/nodes-from-anchor/test/v00/RootNode.test.ts ================================================ import { programNode, rootNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { rootNodeFromAnchorV00 } from '../../src'; test('it creates root nodes', () => { const node = rootNodeFromAnchorV00({ instructions: [], metadata: { address: '1111' }, name: 'myProgram', version: '1.2.3', }); expect(node).toEqual( rootNode( programNode({ name: 'myProgram', origin: 'anchor', publicKey: '1111', version: '1.2.3', }), ), ); }); ================================================ FILE: packages/nodes-from-anchor/test/v00/typeNodes/ArrayTypeNode.test.ts ================================================ import { arrayTypeNode, fixedCountNode, numberTypeNode, prefixedCountNode, remainderCountNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { typeNodeFromAnchorV00 } from '../../../src'; test('it creates array type nodes', () => { expect(typeNodeFromAnchorV00({ array: ['u8', 2] })).toEqual(arrayTypeNode(numberTypeNode('u8'), fixedCountNode(2))); expect(typeNodeFromAnchorV00({ vec: 'u8' })).toEqual( arrayTypeNode(numberTypeNode('u8'), prefixedCountNode(numberTypeNode('u32'))), ); expect(typeNodeFromAnchorV00({ size: 'u16', vec: 'u8' })).toEqual( arrayTypeNode(numberTypeNode('u8'), prefixedCountNode(numberTypeNode('u16'))), ); expect(typeNodeFromAnchorV00({ size: 'remainder', vec: 'u8' })).toEqual( arrayTypeNode(numberTypeNode('u8'), remainderCountNode()), ); }); ================================================ FILE: packages/nodes-from-anchor/test/v00/typeNodes/BooleanTypeNode.test.ts ================================================ import { booleanTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { typeNodeFromAnchorV00 } from '../../../src'; test('it creates boolean type nodes', () => { expect(typeNodeFromAnchorV00('bool')).toEqual(booleanTypeNode()); }); ================================================ FILE: packages/nodes-from-anchor/test/v00/typeNodes/BytesTypeNode.test.ts ================================================ import { bytesTypeNode, numberTypeNode, sizePrefixTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { typeNodeFromAnchorV00 } from '../../../src'; test('it creates bytes type nodes', () => { expect(typeNodeFromAnchorV00('bytes')).toEqual(sizePrefixTypeNode(bytesTypeNode(), numberTypeNode('u32'))); }); ================================================ FILE: packages/nodes-from-anchor/test/v00/typeNodes/EnumTypeNode.test.ts ================================================ import { booleanTypeNode, enumEmptyVariantTypeNode, enumStructVariantTypeNode, enumTupleVariantTypeNode, enumTypeNode, numberTypeNode, structFieldTypeNode, structTypeNode, tupleTypeNode, } from '@codama/nodes'; import { expect, test } from 'vitest'; import { typeNodeFromAnchorV00 } from '../../../src'; test('it creates enum type nodes', () => { const node = typeNodeFromAnchorV00({ kind: 'enum', variants: [ { name: 'variantA' }, // Empty variant. { fields: ['u16', 'bool'], name: 'variantB' }, // Tuple variant. { fields: [{ name: 'age', type: 'u8' }], name: 'variantC' }, // Struct variant. ], }); expect(node).toEqual( enumTypeNode([ enumEmptyVariantTypeNode('variantA'), enumTupleVariantTypeNode('variantB', tupleTypeNode([numberTypeNode('u16'), booleanTypeNode()])), enumStructVariantTypeNode( 'variantC', structTypeNode([structFieldTypeNode({ name: 'age', type: numberTypeNode('u8') })]), ), ]), ); }); test('it creates enum type nodes with custom sizes', () => { const node = typeNodeFromAnchorV00({ kind: 'enum', size: 'u16', variants: [] }); expect(node).toEqual(enumTypeNode([], { size: numberTypeNode('u16') })); }); ================================================ FILE: packages/nodes-from-anchor/test/v00/typeNodes/MapTypeNode.test.ts ================================================ import { booleanTypeNode, fixedCountNode, mapTypeNode, numberTypeNode, prefixedCountNode, remainderCountNode, } from '@codama/nodes'; import { expect, test } from 'vitest'; import { typeNodeFromAnchorV00 } from '../../../src'; test('it creates map type nodes', () => { expect(typeNodeFromAnchorV00({ hashMap: ['u8', 'bool'] })).toEqual( mapTypeNode(numberTypeNode('u8'), booleanTypeNode(), prefixedCountNode(numberTypeNode('u32'))), ); expect(typeNodeFromAnchorV00({ hashMap: ['u8', 'bool'], size: 2 })).toEqual( mapTypeNode(numberTypeNode('u8'), booleanTypeNode(), fixedCountNode(2)), ); expect(typeNodeFromAnchorV00({ hashMap: ['u8', 'bool'], size: 'u16' })).toEqual( mapTypeNode(numberTypeNode('u8'), booleanTypeNode(), prefixedCountNode(numberTypeNode('u16'))), ); expect(typeNodeFromAnchorV00({ hashMap: ['u8', 'bool'], size: 'remainder' })).toEqual( mapTypeNode(numberTypeNode('u8'), booleanTypeNode(), remainderCountNode()), ); }); ================================================ FILE: packages/nodes-from-anchor/test/v00/typeNodes/NumberTypeNode.test.ts ================================================ import { numberTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { typeNodeFromAnchorV00 } from '../../../src'; test('it creates number type nodes', () => { expect(typeNodeFromAnchorV00('f32')).toEqual(numberTypeNode('f32')); expect(typeNodeFromAnchorV00('f64')).toEqual(numberTypeNode('f64')); expect(typeNodeFromAnchorV00('i8')).toEqual(numberTypeNode('i8')); expect(typeNodeFromAnchorV00('i16')).toEqual(numberTypeNode('i16')); expect(typeNodeFromAnchorV00('i32')).toEqual(numberTypeNode('i32')); expect(typeNodeFromAnchorV00('i64')).toEqual(numberTypeNode('i64')); expect(typeNodeFromAnchorV00('i128')).toEqual(numberTypeNode('i128')); expect(typeNodeFromAnchorV00('shortU16')).toEqual(numberTypeNode('shortU16')); expect(typeNodeFromAnchorV00('u8')).toEqual(numberTypeNode('u8')); expect(typeNodeFromAnchorV00('u16')).toEqual(numberTypeNode('u16')); expect(typeNodeFromAnchorV00('u32')).toEqual(numberTypeNode('u32')); expect(typeNodeFromAnchorV00('u64')).toEqual(numberTypeNode('u64')); expect(typeNodeFromAnchorV00('u128')).toEqual(numberTypeNode('u128')); }); ================================================ FILE: packages/nodes-from-anchor/test/v00/typeNodes/OptionTypeNode.test.ts ================================================ import { numberTypeNode, optionTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { typeNodeFromAnchorV00 } from '../../../src'; test('it creates option type nodes', () => { expect(typeNodeFromAnchorV00({ option: 'u8' })).toEqual(optionTypeNode(numberTypeNode('u8'))); }); test('it creates option type nodes with custom prefixes', () => { expect(typeNodeFromAnchorV00({ option: 'u8', prefix: 'u64' })).toEqual( optionTypeNode(numberTypeNode('u8'), { prefix: numberTypeNode('u64') }), ); }); test('it creates option type nodes with fixed size', () => { expect(typeNodeFromAnchorV00({ coption: 'u8' })).toEqual( optionTypeNode(numberTypeNode('u8'), { fixed: true, prefix: numberTypeNode('u32') }), ); expect(typeNodeFromAnchorV00({ coption: 'u8', prefix: 'u16' })).toEqual( optionTypeNode(numberTypeNode('u8'), { fixed: true, prefix: numberTypeNode('u16') }), ); }); ================================================ FILE: packages/nodes-from-anchor/test/v00/typeNodes/PublicKeyTypeNode.test.ts ================================================ import { publicKeyTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { typeNodeFromAnchorV00 } from '../../../src'; test('it creates public key type nodes', () => { expect(typeNodeFromAnchorV00('publicKey')).toEqual(publicKeyTypeNode()); }); ================================================ FILE: packages/nodes-from-anchor/test/v00/typeNodes/SetTypeNode.test.ts ================================================ import { fixedCountNode, numberTypeNode, prefixedCountNode, remainderCountNode, setTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { typeNodeFromAnchorV00 } from '../../../src'; test('it creates set type nodes', () => { expect(typeNodeFromAnchorV00({ hashSet: 'u8' })).toEqual( setTypeNode(numberTypeNode('u8'), prefixedCountNode(numberTypeNode('u32'))), ); expect(typeNodeFromAnchorV00({ hashSet: 'u8', size: 2 })).toEqual( setTypeNode(numberTypeNode('u8'), fixedCountNode(2)), ); expect(typeNodeFromAnchorV00({ hashSet: 'u8', size: 'u16' })).toEqual( setTypeNode(numberTypeNode('u8'), prefixedCountNode(numberTypeNode('u16'))), ); expect(typeNodeFromAnchorV00({ hashSet: 'u8', size: 'remainder' })).toEqual( setTypeNode(numberTypeNode('u8'), remainderCountNode()), ); }); ================================================ FILE: packages/nodes-from-anchor/test/v00/typeNodes/StringTypeNode.test.ts ================================================ import { numberTypeNode, sizePrefixTypeNode, stringTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { typeNodeFromAnchorV00 } from '../../../src'; test('it creates string type nodes', () => { expect(typeNodeFromAnchorV00('string')).toEqual(sizePrefixTypeNode(stringTypeNode('utf8'), numberTypeNode('u32'))); }); ================================================ FILE: packages/nodes-from-anchor/test/v00/typeNodes/StructTypeNode.test.ts ================================================ import { numberTypeNode, sizePrefixTypeNode, stringTypeNode, structFieldTypeNode, structTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { typeNodeFromAnchorV00 } from '../../../src'; test('it creates struct type nodes', () => { const node = typeNodeFromAnchorV00({ fields: [ { name: 'name', type: 'string' }, { name: 'age', type: 'u8' }, ], kind: 'struct', }); expect(node).toEqual( structTypeNode([ structFieldTypeNode({ name: 'name', type: sizePrefixTypeNode(stringTypeNode('utf8'), numberTypeNode('u32')), }), structFieldTypeNode({ name: 'age', type: numberTypeNode('u8') }), ]), ); }); ================================================ FILE: packages/nodes-from-anchor/test/v00/typeNodes/TupleTypeNode.test.ts ================================================ import { numberTypeNode, publicKeyTypeNode, tupleTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { typeNodeFromAnchorV00 } from '../../../src'; test('it creates tuple type nodes', () => { const node = typeNodeFromAnchorV00({ tuple: ['u8', 'publicKey'], }); expect(node).toEqual(tupleTypeNode([numberTypeNode('u8'), publicKeyTypeNode()])); }); ================================================ FILE: packages/nodes-from-anchor/test/v01/AccountNode.test.ts ================================================ import { accountNode, bytesTypeNode, fieldDiscriminatorNode, fixedSizeTypeNode, numberTypeNode, structFieldTypeNode, structTypeNode, } from '@codama/nodes'; import { expect, test } from 'vitest'; import { accountNodeFromAnchorV01, GenericsV01, getAnchorDiscriminatorV01 } from '../../src'; const generics = {} as GenericsV01; test('it creates account nodes with anchor discriminators', () => { const node = accountNodeFromAnchorV01( { discriminator: [246, 28, 6, 87, 251, 45, 50, 42], name: 'MyAccount', }, [ { docs: [], name: 'MyAccount', type: { fields: [ { name: 'name', type: 'u32', }, ], kind: 'struct', }, }, ], generics, ); expect(node).toEqual( accountNode({ data: structTypeNode([ structFieldTypeNode({ defaultValue: getAnchorDiscriminatorV01([246, 28, 6, 87, 251, 45, 50, 42]), defaultValueStrategy: 'omitted', name: 'discriminator', type: fixedSizeTypeNode(bytesTypeNode(), 8), }), structFieldTypeNode({ name: 'name', type: numberTypeNode('u32'), }), ]), discriminators: [fieldDiscriminatorNode('discriminator')], name: 'myAccount', }), ); }); ================================================ FILE: packages/nodes-from-anchor/test/v01/DefinedTypeNode.test.ts ================================================ /* eslint-disable sort-keys-fix/sort-keys-fix */ import { definedTypeNode, numberTypeNode, structFieldTypeNode, structTypeNode, tupleTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { definedTypeNodeFromAnchorV01, GenericsV01 } from '../../src'; test('it creates defined type nodes', () => { const node = definedTypeNodeFromAnchorV01( { name: 'MyType', type: { fields: [{ name: 'my_field', type: 'u64' }], kind: 'struct', }, }, {} as GenericsV01, ); expect(node).toEqual( definedTypeNode({ name: 'myType', type: structTypeNode([ structFieldTypeNode({ name: 'myField', type: numberTypeNode('u64'), }), ]), }), ); }); test('it unwraps generic arguments', () => { const node = definedTypeNodeFromAnchorV01( { name: 'Buffer', type: { fields: [{ name: 'data', type: { generic: 'T' } }], kind: 'struct', }, }, { constArgs: {}, typeArgs: { T: { name: 'T', kind: 'type', type: 'u64' } }, types: {}, }, ); expect(node).toEqual( definedTypeNode({ name: 'buffer', type: structTypeNode([ structFieldTypeNode({ name: 'data', type: numberTypeNode('u64'), }), ]), }), ); }); test('it unwraps nested generic types', () => { const node = definedTypeNodeFromAnchorV01( { name: 'Buffer', type: { fields: [{ name: 'data', type: { generic: 'T' } }], kind: 'struct', }, }, { constArgs: {}, typeArgs: { T: { name: 'T', kind: 'type', type: { defined: { name: 'PrefixedData', generics: [{ kind: 'type', type: 'u8' }] } }, }, }, types: { PrefixedData: { name: 'PrefixedData', generics: [{ name: 'T', kind: 'type' }], type: { fields: ['u64', { generic: 'T' }], kind: 'struct', }, }, }, }, ); expect(node).toEqual( definedTypeNode({ name: 'buffer', type: structTypeNode([ structFieldTypeNode({ name: 'data', type: tupleTypeNode([numberTypeNode('u64'), numberTypeNode('u8')]), }), ]), }), ); }); ================================================ FILE: packages/nodes-from-anchor/test/v01/ErrorNode.test.ts ================================================ import { errorNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { errorNodeFromAnchorV01 } from '../../src'; test('it creates error nodes', () => { const node = errorNodeFromAnchorV01({ code: 42, msg: 'my error message', name: 'myError', }); expect(node).toEqual( errorNode({ code: 42, docs: ['myError: my error message'], message: 'my error message', name: 'myError', }), ); }); ================================================ FILE: packages/nodes-from-anchor/test/v01/EventNode.test.ts ================================================ import { CODAMA_ERROR__ANCHOR__EVENT_TYPE_MISSING, CodamaError } from '@codama/errors'; import { constantDiscriminatorNode, constantValueNode } from '@codama/nodes'; import { bytesTypeNode, eventNode, fixedSizeTypeNode, hiddenPrefixTypeNode, numberTypeNode, structFieldTypeNode, structTypeNode, tupleTypeNode, } from '@codama/nodes'; import { expect, test } from 'vitest'; import { eventNodeFromAnchorV01, GenericsV01, getAnchorDiscriminatorV01 } from '../../src'; const generics = {} as GenericsV01; test('it creates event nodes with anchor discriminators', () => { const node = eventNodeFromAnchorV01( { discriminator: [246, 28, 6, 87, 251, 45, 50, 42], name: 'MyEvent', }, [ { docs: [], name: 'MyEvent', type: { fields: [ { name: 'amount', type: 'u32', }, ], kind: 'struct', }, }, ], generics, ); expect(node).toEqual( eventNode({ data: hiddenPrefixTypeNode( structTypeNode([structFieldTypeNode({ name: 'amount', type: numberTypeNode('u32') })]), [ constantValueNode( fixedSizeTypeNode(bytesTypeNode(), 8), getAnchorDiscriminatorV01([246, 28, 6, 87, 251, 45, 50, 42]), ), ], ), discriminators: [ constantDiscriminatorNode( constantValueNode( fixedSizeTypeNode(bytesTypeNode(), 8), getAnchorDiscriminatorV01([246, 28, 6, 87, 251, 45, 50, 42]), ), ), ], name: 'myEvent', }), ); }); test('it creates tuple event nodes with anchor discriminators', () => { const node = eventNodeFromAnchorV01( { discriminator: [246, 28, 6, 87, 251, 45, 50, 42], name: 'TupleEvent', }, [ { docs: [], name: 'TupleEvent', type: { fields: ['u32', 'u64'], kind: 'struct', }, }, ], generics, ); expect(node).toEqual( eventNode({ data: hiddenPrefixTypeNode(tupleTypeNode([numberTypeNode('u32'), numberTypeNode('u64')]), [ constantValueNode( fixedSizeTypeNode(bytesTypeNode(), 8), getAnchorDiscriminatorV01([246, 28, 6, 87, 251, 45, 50, 42]), ), ]), discriminators: [ constantDiscriminatorNode( constantValueNode( fixedSizeTypeNode(bytesTypeNode(), 8), getAnchorDiscriminatorV01([246, 28, 6, 87, 251, 45, 50, 42]), ), ), ], name: 'tupleEvent', }), ); }); test('it throws when the backing event type is missing', () => { expect(() => eventNodeFromAnchorV01( { discriminator: [246, 28, 6, 87, 251, 45, 50, 42], name: 'MissingEvent', }, [], generics, ), ).toThrow(new CodamaError(CODAMA_ERROR__ANCHOR__EVENT_TYPE_MISSING, { name: 'MissingEvent' })); }); ================================================ FILE: packages/nodes-from-anchor/test/v01/InstructionAccountNode.test.ts ================================================ import { accountValueNode, argumentValueNode, constantPdaSeedNodeFromBytes, instructionAccountNode, instructionArgumentNode, numberTypeNode, pdaNode, pdaSeedValueNode, pdaValueNode, publicKeyTypeNode, publicKeyValueNode, variablePdaSeedNode, } from '@codama/nodes'; import { expect, test } from 'vitest'; import { IdlV01InstructionAccountItem, instructionAccountNodeFromAnchorV01, instructionAccountNodesFromAnchorV01, } from '../../src'; test('it creates instruction account nodes', () => { const node = instructionAccountNodeFromAnchorV01( { docs: ['my docs'], name: 'MyInstructionAccount', optional: true, signer: false, writable: true, }, [], ); expect(node).toEqual( instructionAccountNode({ docs: ['my docs'], isOptional: true, isSigner: false, isWritable: true, name: 'myInstructionAccount', }), ); }); test('it flattens nested instruction accounts without prefixing when no duplicates exist', () => { const nodes = instructionAccountNodesFromAnchorV01( [ { name: 'accountA', signer: false, writable: false }, { accounts: [ { name: 'account_b', signer: false, writable: true, }, { name: 'account_c', pda: { seeds: [ { kind: 'const', value: [0, 1, 2, 3], }, { kind: 'account', path: 'account_b', }, { kind: 'arg', path: 'amount', }, ], }, signer: true, writable: false, }, { address: '11111111111111111111111111111111', name: 'system_program', }, ], name: 'nested', }, { name: 'account_d', signer: true, writable: true }, ], [instructionArgumentNode({ name: 'amount', type: numberTypeNode('u8') })], ); expect(nodes).toEqual([ instructionAccountNode({ isSigner: false, isWritable: false, name: 'accountA' }), instructionAccountNode({ isSigner: false, isWritable: true, name: 'accountB' }), instructionAccountNode({ defaultValue: pdaValueNode( pdaNode({ name: 'accountC', seeds: [ constantPdaSeedNodeFromBytes('base58', '1Ldp'), variablePdaSeedNode('accountB', publicKeyTypeNode()), variablePdaSeedNode('amount', numberTypeNode('u8')), ], }), [ pdaSeedValueNode('accountB', accountValueNode('accountB')), pdaSeedValueNode('amount', argumentValueNode('amount')), ], ), isSigner: true, isWritable: false, name: 'accountC', }), instructionAccountNode({ defaultValue: publicKeyValueNode('11111111111111111111111111111111', 'systemProgram'), isSigner: false, isWritable: false, name: 'systemProgram', }), instructionAccountNode({ isSigner: true, isWritable: true, name: 'accountD' }), ]); }); test('it prevents duplicate names by prefixing nested accounts with different parent names', () => { const nodes = instructionAccountNodesFromAnchorV01( [ { accounts: [ { name: 'mint', signer: false, writable: false }, { name: 'authority', signer: true, writable: false }, ], name: 'tokenProgram', }, { accounts: [ { name: 'mint', signer: false, writable: true }, { name: 'metadata', signer: false, writable: true }, ], name: 'nftProgram', }, ], [], ); expect(nodes).toEqual([ instructionAccountNode({ isSigner: false, isWritable: false, name: 'tokenProgramMint' }), instructionAccountNode({ isSigner: true, isWritable: false, name: 'tokenProgramAuthority' }), instructionAccountNode({ isSigner: false, isWritable: true, name: 'nftProgramMint' }), instructionAccountNode({ isSigner: false, isWritable: true, name: 'nftProgramMetadata' }), ]); }); test('it handles nested accounts with more complex duplicate scenarios', () => { const nodes = instructionAccountNodesFromAnchorV01( [ { name: 'authority', signer: true, writable: false }, { accounts: [ { name: 'mint', signer: false, writable: false }, { name: 'vault', signer: false, writable: true }, { name: 'authority', signer: false, writable: false }, ], name: 'sourceProgram', }, { accounts: [ { name: 'mint', signer: false, writable: false }, { name: 'escrow', signer: false, writable: true }, { name: 'metadata', signer: false, writable: true }, ], name: 'destinationProgram', }, ], [], ); expect(nodes).toEqual([ instructionAccountNode({ isSigner: true, isWritable: false, name: 'authority' }), instructionAccountNode({ isSigner: false, isWritable: false, name: 'sourceProgramMint' }), instructionAccountNode({ isSigner: false, isWritable: true, name: 'sourceProgramVault' }), instructionAccountNode({ isSigner: false, isWritable: false, name: 'sourceProgramAuthority' }), instructionAccountNode({ isSigner: false, isWritable: false, name: 'destinationProgramMint' }), instructionAccountNode({ isSigner: false, isWritable: true, name: 'destinationProgramEscrow' }), instructionAccountNode({ isSigner: false, isWritable: true, name: 'destinationProgramMetadata' }), ]); }); test('it handles depth-2 nested accounts with naming conflicts', () => { const items = [ { name: 'authority', signer: true, writable: false }, { accounts: [ { name: 'mint', signer: false, writable: false }, { name: 'vault', signer: false, writable: true }, { name: 'authority', signer: false, writable: false }, { accounts: [ { name: 'authority', signer: false, writable: true }, { name: 'mint', signer: false, writable: false }, ], name: 'deepProgram', }, ], name: 'sourceProgram', }, { accounts: [ { name: 'mint', signer: false, writable: false }, { name: 'escrow', signer: false, writable: true }, { name: 'metadata', signer: false, writable: true }, ], name: 'destinationProgram', }, ] as unknown as IdlV01InstructionAccountItem[]; const nodes = instructionAccountNodesFromAnchorV01(items, []); expect(nodes).toEqual([ instructionAccountNode({ isSigner: true, isWritable: false, name: 'authority' }), instructionAccountNode({ isSigner: false, isWritable: false, name: 'sourceProgramMint' }), instructionAccountNode({ isSigner: false, isWritable: true, name: 'sourceProgramVault' }), instructionAccountNode({ isSigner: false, isWritable: false, name: 'sourceProgramAuthority' }), instructionAccountNode({ isSigner: false, isWritable: true, name: 'sourceProgramDeepProgramAuthority' }), instructionAccountNode({ isSigner: false, isWritable: false, name: 'sourceProgramDeepProgramMint' }), instructionAccountNode({ isSigner: false, isWritable: false, name: 'destinationProgramMint' }), instructionAccountNode({ isSigner: false, isWritable: true, name: 'destinationProgramEscrow' }), instructionAccountNode({ isSigner: false, isWritable: true, name: 'destinationProgramMetadata' }), ]); }); test('it correctly prefixes PDA seed account references in nested groups', () => { const nodes = instructionAccountNodesFromAnchorV01( [ { accounts: [ { name: 'mint', signer: false, writable: false }, { name: 'vault', pda: { seeds: [{ kind: 'account', path: 'mint' }], }, signer: false, writable: true, }, ], name: 'tokenProgram', }, { accounts: [ { name: 'mint', signer: false, writable: false }, { name: 'escrow', pda: { seeds: [{ kind: 'account', path: 'mint' }], }, signer: false, writable: true, }, ], name: 'nftProgram', }, ], [], ); expect(nodes).toEqual([ instructionAccountNode({ isSigner: false, isWritable: false, name: 'tokenProgramMint' }), instructionAccountNode({ defaultValue: pdaValueNode( pdaNode({ name: 'tokenProgramVault', seeds: [variablePdaSeedNode('tokenProgramMint', publicKeyTypeNode())], }), [pdaSeedValueNode('tokenProgramMint', accountValueNode('tokenProgramMint'))], ), isSigner: false, isWritable: true, name: 'tokenProgramVault', }), instructionAccountNode({ isSigner: false, isWritable: false, name: 'nftProgramMint' }), instructionAccountNode({ defaultValue: pdaValueNode( pdaNode({ name: 'nftProgramEscrow', seeds: [variablePdaSeedNode('nftProgramMint', publicKeyTypeNode())], }), [pdaSeedValueNode('nftProgramMint', accountValueNode('nftProgramMint'))], ), isSigner: false, isWritable: true, name: 'nftProgramEscrow', }), ]); }); test('it ignores PDA default values if at least one seed as a path of length greater than 1', () => { const nodes = instructionAccountNodesFromAnchorV01( // [ // accountNode({ // data: sizePrefixTypeNode( // structTypeNode([structFieldTypeNode({ name: 'authority', type: publicKeyTypeNode() })]), // numberTypeNode('u32'), // ), // name: 'mint', // }), // ], [ { name: 'somePdaAccount', pda: { seeds: [ { account: 'mint', kind: 'account', path: 'mint.authority', }, ], }, signer: false, writable: false, }, ], [], ); expect(nodes).toEqual([ instructionAccountNode({ isSigner: false, isWritable: false, name: 'somePdaAccount', }), ]); }); test('it handles PDAs with a constant program id', () => { const nodes = instructionAccountNodesFromAnchorV01( [ { name: 'program_data', pda: { program: { kind: 'const', value: [ 2, 168, 246, 145, 78, 136, 161, 176, 226, 16, 21, 62, 247, 99, 174, 43, 0, 194, 185, 61, 22, 193, 36, 210, 192, 83, 122, 16, 4, 128, 0, 0, ], }, seeds: [ { kind: 'const', value: [ 166, 175, 151, 238, 166, 67, 87, 148, 114, 209, 13, 88, 186, 228, 206, 197, 182, 71, 129, 195, 206, 236, 229, 223, 184, 60, 97, 249, 63, 92, 203, 27, ], }, ], }, }, ], [], ); expect(nodes).toEqual([ instructionAccountNode({ defaultValue: pdaValueNode( pdaNode({ name: 'programData', programId: 'BPFLoaderUpgradeab1e11111111111111111111111', seeds: [constantPdaSeedNodeFromBytes('base58', 'CDfyUBS8ZuL1L3kEy6mHVyAx1s9E97KNAwTfMfvhCriN')], }), [], ), isSigner: false, isWritable: false, name: 'programData', }), ]); }); test('it handles PDAs with a program id that points to another account', () => { const nodes = instructionAccountNodesFromAnchorV01( [ { name: 'my_pda', pda: { program: { kind: 'account', path: 'my_program' }, seeds: [], }, }, ], [], ); expect(nodes).toEqual([ instructionAccountNode({ defaultValue: pdaValueNode( pdaNode({ name: 'myPda', seeds: [], }), [], accountValueNode('myProgram'), ), isSigner: false, isWritable: false, name: 'myPda', }), ]); }); test.skip('it handles account data paths of length 2', () => { const nodes = instructionAccountNodesFromAnchorV01( // [ // accountNode({ // data: sizePrefixTypeNode( // structTypeNode([structFieldTypeNode({ name: 'authority', type: publicKeyTypeNode() })]), // numberTypeNode('u32'), // ), // name: 'mint', // }), // ], [ { name: 'somePdaAccount', pda: { seeds: [ { account: 'mint', kind: 'account', path: 'mint.authority', }, ], }, signer: false, writable: false, }, ], [], ); expect(nodes).toEqual([ instructionAccountNode({ defaultValue: pdaValueNode( pdaNode({ name: 'somePdaAccount', seeds: [variablePdaSeedNode('mintAuthority', publicKeyTypeNode())], }), [], ), isSigner: false, isWritable: false, name: 'somePdaAccount', }), ]); }); ================================================ FILE: packages/nodes-from-anchor/test/v01/InstructionArgumentNode.test.ts ================================================ import { instructionArgumentNode, numberTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { GenericsV01, instructionArgumentNodeFromAnchorV01 } from '../../src'; const generics = {} as GenericsV01; test('it creates instruction argument nodes', () => { const node = instructionArgumentNodeFromAnchorV01( { name: 'my_instruction_argument', type: 'u8', }, generics, ); expect(node).toEqual( instructionArgumentNode({ name: 'myInstructionArgument', type: numberTypeNode('u8'), }), ); }); ================================================ FILE: packages/nodes-from-anchor/test/v01/InstructionNode.test.ts ================================================ import { bytesTypeNode, fieldDiscriminatorNode, fixedSizeTypeNode, instructionAccountNode, instructionArgumentNode, instructionNode, numberTypeNode, } from '@codama/nodes'; import { expect, test } from 'vitest'; import { GenericsV01, getAnchorDiscriminatorV01, instructionNodeFromAnchorV01 } from '../../src'; const generics = {} as GenericsV01; test('it creates instruction nodes', () => { const node = instructionNodeFromAnchorV01( { accounts: [ { name: 'distribution', pda: { seeds: [ { kind: 'const', value: [42, 31, 29] }, { account: 'Distribution', kind: 'account', path: 'distribution.group_mint' }, ], }, signer: false, writable: true, }, ], args: [{ name: 'amount', type: 'u8' }], discriminator: [246, 28, 6, 87, 251, 45, 50, 42], name: 'mintTokens', }, generics, ); expect(node).toEqual( instructionNode({ accounts: [ instructionAccountNode({ // TODO: Handle seeds with nested paths. (Needs a path in the IDL but should we?) // defaultValue: pdaValueNode( // pdaNode({ // name: 'distribution', // seeds: [ // constantPdaSeedNodeFromBytes('base58', 'F9bS'), // variablePdaSeedNode('distributionGroupMint', publicKeyTypeNode()), // ], // }), // [pdaSeedValueNode("distributionGroupMint", accountValueNode('distribution', 'group_mint'))], // ), isSigner: false, isWritable: true, name: 'distribution', }), ], arguments: [ instructionArgumentNode({ defaultValue: getAnchorDiscriminatorV01([246, 28, 6, 87, 251, 45, 50, 42]), defaultValueStrategy: 'omitted', name: 'discriminator', type: fixedSizeTypeNode(bytesTypeNode(), 8), }), instructionArgumentNode({ name: 'amount', type: numberTypeNode('u8') }), ], discriminators: [fieldDiscriminatorNode('discriminator')], name: 'mintTokens', }), ); }); test('it creates instruction nodes with anchor discriminators', () => { const node = instructionNodeFromAnchorV01( { accounts: [], args: [], discriminator: [246, 28, 6, 87, 251, 45, 50, 42], name: 'myInstruction', }, generics, ); expect(node).toEqual( instructionNode({ arguments: [ instructionArgumentNode({ defaultValue: getAnchorDiscriminatorV01([246, 28, 6, 87, 251, 45, 50, 42]), defaultValueStrategy: 'omitted', name: 'discriminator', type: fixedSizeTypeNode(bytesTypeNode(), 8), }), ], discriminators: [fieldDiscriminatorNode('discriminator')], name: 'myInstruction', }), ); }); ================================================ FILE: packages/nodes-from-anchor/test/v01/ProgramNode.test.ts ================================================ import { accountNode, accountValueNode, argumentValueNode, arrayTypeNode, bytesTypeNode, constantDiscriminatorNode, constantPdaSeedNodeFromBytes, constantValueNode, definedTypeLinkNode, definedTypeNode, enumEmptyVariantTypeNode, enumTupleVariantTypeNode, enumTypeNode, errorNode, eventNode, fieldDiscriminatorNode, fixedCountNode, fixedSizeTypeNode, hiddenPrefixTypeNode, instructionAccountNode, instructionArgumentNode, instructionNode, numberTypeNode, pdaNode, pdaSeedValueNode, pdaValueNode, programNode, publicKeyTypeNode, structFieldTypeNode, structTypeNode, tupleTypeNode, variablePdaSeedNode, } from '@codama/nodes'; import { expect, test } from 'vitest'; import { getAnchorDiscriminatorV01, programNodeFromAnchorV01 } from '../../src'; test('it creates program nodes', () => { const node = programNodeFromAnchorV01({ accounts: [{ discriminator: [246, 28, 6, 87, 251, 45, 50, 42], name: 'MyAccount' }], address: '1111', errors: [{ code: 42, msg: 'my error message', name: 'myError' }], events: [{ discriminator: [1, 2, 3, 4, 5, 6, 7, 8], name: 'MyEvent' }], instructions: [ { accounts: [ { name: 'authority', pda: { seeds: [ { kind: 'const', value: [42, 31, 29] }, { kind: 'account', path: 'owner' }, { kind: 'arg', path: 'amount' }, ], }, }, { name: 'owner', }, { name: 'some_account', }, ], args: [ { name: 'amount', type: 'u8', }, ], discriminator: [246, 28, 6, 87, 251, 45, 50, 42], name: 'my_instruction', }, ], metadata: { name: 'my_program', spec: '0.1.0', version: '1.2.3' }, types: [ { name: 'MyAccount', type: { fields: [{ name: 'delegate', type: 'pubkey' }], kind: 'struct' } }, { name: 'MyEvent', type: { fields: [{ name: 'amount', type: 'u64' }], kind: 'struct' } }, ], }); expect(node).toEqual( programNode({ accounts: [ accountNode({ data: structTypeNode([ structFieldTypeNode({ defaultValue: getAnchorDiscriminatorV01([246, 28, 6, 87, 251, 45, 50, 42]), defaultValueStrategy: 'omitted', name: 'discriminator', type: fixedSizeTypeNode(bytesTypeNode(), 8), }), structFieldTypeNode({ name: 'delegate', type: publicKeyTypeNode(), }), ]), discriminators: [fieldDiscriminatorNode('discriminator')], name: 'myAccount', }), ], definedTypes: [], errors: [ errorNode({ code: 42, docs: ['myError: my error message'], message: 'my error message', name: 'myError', }), ], events: [ eventNode({ data: hiddenPrefixTypeNode( structTypeNode([ structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64'), }), ]), [ constantValueNode( fixedSizeTypeNode(bytesTypeNode(), 8), getAnchorDiscriminatorV01([1, 2, 3, 4, 5, 6, 7, 8]), ), ], ), discriminators: [ constantDiscriminatorNode( constantValueNode( fixedSizeTypeNode(bytesTypeNode(), 8), getAnchorDiscriminatorV01([1, 2, 3, 4, 5, 6, 7, 8]), ), ), ], name: 'myEvent', }), ], instructions: [ instructionNode({ accounts: [ instructionAccountNode({ defaultValue: pdaValueNode( pdaNode({ name: 'authority', seeds: [ constantPdaSeedNodeFromBytes('base58', 'F9bS'), variablePdaSeedNode('owner', publicKeyTypeNode()), variablePdaSeedNode('amount', numberTypeNode('u8')), ], }), [ pdaSeedValueNode('owner', accountValueNode('owner')), pdaSeedValueNode('amount', argumentValueNode('amount')), ], ), isSigner: false, isWritable: false, name: 'authority', }), instructionAccountNode({ isSigner: false, isWritable: false, name: 'owner', }), instructionAccountNode({ isSigner: false, isWritable: false, name: 'someAccount', }), ], arguments: [ instructionArgumentNode({ defaultValue: getAnchorDiscriminatorV01([246, 28, 6, 87, 251, 45, 50, 42]), defaultValueStrategy: 'omitted', name: 'discriminator', type: fixedSizeTypeNode(bytesTypeNode(), 8), }), instructionArgumentNode({ name: 'amount', type: numberTypeNode('u8') }), ], discriminators: [fieldDiscriminatorNode('discriminator')], name: 'myInstruction', }), ], name: 'myProgram', origin: 'anchor', pdas: [], publicKey: '1111', version: '1.2.3', }), ); }); test('it unwraps and removes generic types', () => { const node = programNodeFromAnchorV01({ address: '1111', instructions: [], metadata: { name: 'my_program', spec: '0.1.0', version: '1.2.3' }, types: [ { generics: [ { kind: 'const', name: 'N', type: 'usize' }, { kind: 'type', name: 'T' }, ], name: 'SimpleAllocator', type: { fields: [ { name: 'state', type: { array: [{ defined: { name: 'ItemState' } }, { generic: 'N' }] }, }, { name: 'data', type: { array: [{ generic: 'T' }, { generic: 'N' }] }, }, ], kind: 'struct', }, }, { name: 'AccountData', type: { kind: 'enum', variants: [ { name: 'Unknown' }, { fields: [ { defined: { generics: [ { kind: 'const', value: '1000' }, { kind: 'type', type: { defined: { name: 'VirtualTimelockAccount' } } }, ], name: 'SimpleAllocator', }, }, ], name: 'Timelock', }, { fields: [ { defined: { generics: [ { kind: 'const', value: '500' }, { kind: 'type', type: { defined: { name: 'VirtualDurableNonce' } } }, ], name: 'SimpleAllocator', }, }, ], name: 'Nonce', }, { fields: [ { defined: { generics: [ { kind: 'const', value: '250' }, { kind: 'type', type: { defined: { name: 'VirtualRelayAccount' } } }, ], name: 'SimpleAllocator', }, }, ], name: 'Relay', }, ], }, }, ], }); expect(node).toEqual( programNode({ definedTypes: [ definedTypeNode({ name: 'AccountData', type: enumTypeNode([ enumEmptyVariantTypeNode('unknown'), enumTupleVariantTypeNode( 'timelock', tupleTypeNode([ structTypeNode([ structFieldTypeNode({ name: 'state', type: arrayTypeNode(definedTypeLinkNode('itemState'), fixedCountNode(1000)), }), structFieldTypeNode({ name: 'data', type: arrayTypeNode( definedTypeLinkNode('virtualTimelockAccount'), fixedCountNode(1000), ), }), ]), ]), ), enumTupleVariantTypeNode( 'nonce', tupleTypeNode([ structTypeNode([ structFieldTypeNode({ name: 'state', type: arrayTypeNode(definedTypeLinkNode('itemState'), fixedCountNode(500)), }), structFieldTypeNode({ name: 'data', type: arrayTypeNode( definedTypeLinkNode('virtualDurableNonce'), fixedCountNode(500), ), }), ]), ]), ), enumTupleVariantTypeNode( 'relay', tupleTypeNode([ structTypeNode([ structFieldTypeNode({ name: 'state', type: arrayTypeNode(definedTypeLinkNode('itemState'), fixedCountNode(250)), }), structFieldTypeNode({ name: 'data', type: arrayTypeNode( definedTypeLinkNode('virtualRelayAccount'), fixedCountNode(250), ), }), ]), ]), ), ]), }), ], name: 'myProgram', origin: 'anchor', pdas: [], publicKey: '1111', version: '1.2.3', }), ); }); ================================================ FILE: packages/nodes-from-anchor/test/v01/RootNode.test.ts ================================================ import { programNode, rootNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { rootNodeFromAnchorV01 } from '../../src'; test('it creates root nodes', () => { const node = rootNodeFromAnchorV01({ address: '1111', instructions: [], metadata: { name: 'myProgram', spec: '0.1.0', version: '1.2.3', }, }); expect(node).toEqual( rootNode( programNode({ name: 'myProgram', origin: 'anchor', publicKey: '1111', version: '1.2.3', }), ), ); }); ================================================ FILE: packages/nodes-from-anchor/test/v01/extractPdasVisitor.test.ts ================================================ import { accountValueNode, constantPdaSeedNodeFromBytes, instructionAccountNode, instructionNode, pdaLinkNode, pdaNode, pdaSeedValueNode, pdaValueNode, programNode, publicKeyTypeNode, variablePdaSeedNode, } from '@codama/nodes'; import { expect, test, vi } from 'vitest'; import { extractPdasFromProgram } from '../../src/extractPdasVisitor'; function makeProgram(instructions: ReturnType[]) { return programNode({ instructions, name: 'testProgram', publicKey: '1111', }); } test('it extracts a single PDA to program level', () => { const program = makeProgram([ instructionNode({ accounts: [ instructionAccountNode({ defaultValue: pdaValueNode( pdaNode({ name: 'myPda', seeds: [constantPdaSeedNodeFromBytes('base58', 'F9bS')], }), [], ), isSigner: false, isWritable: false, name: 'myPda', }), ], name: 'myInstruction', }), ]); const result = extractPdasFromProgram(program); expect(result.pdas).toEqual([ pdaNode({ name: 'myPda', seeds: [constantPdaSeedNodeFromBytes('base58', 'F9bS')], }), ]); expect(result.instructions[0].accounts[0].defaultValue).toEqual(pdaValueNode(pdaLinkNode('myPda'), [])); }); test('it deduplicates the same PDA across two instructions', () => { const seeds = [constantPdaSeedNodeFromBytes('base58', 'F9bS'), variablePdaSeedNode('owner', publicKeyTypeNode())]; const program = makeProgram([ instructionNode({ accounts: [ instructionAccountNode({ defaultValue: pdaValueNode(pdaNode({ name: 'myPda', seeds }), [ pdaSeedValueNode('owner', accountValueNode('owner')), ]), isSigner: false, isWritable: false, name: 'myPda', }), instructionAccountNode({ isSigner: false, isWritable: false, name: 'owner' }), ], name: 'instructionA', }), instructionNode({ accounts: [ instructionAccountNode({ defaultValue: pdaValueNode(pdaNode({ name: 'myPda', seeds }), [ pdaSeedValueNode('owner', accountValueNode('owner')), ]), isSigner: false, isWritable: false, name: 'myPda', }), instructionAccountNode({ isSigner: false, isWritable: false, name: 'owner' }), ], name: 'instructionB', }), ]); const result = extractPdasFromProgram(program); // Only one PDA extracted. expect(result.pdas).toHaveLength(1); expect(result.pdas[0].name).toBe('myPda'); // Both instructions use pdaLinkNode. for (const ix of result.instructions) { const account = ix.accounts[0]; expect(account.defaultValue).toEqual( pdaValueNode(pdaLinkNode('myPda'), [pdaSeedValueNode('owner', accountValueNode('owner'))]), ); } }); test('it handles name collisions with different seeds by suffixing', () => { const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}); const program = makeProgram([ instructionNode({ accounts: [ instructionAccountNode({ defaultValue: pdaValueNode( pdaNode({ name: 'authority', seeds: [constantPdaSeedNodeFromBytes('base58', 'F9bS')], }), [], ), isSigner: false, isWritable: false, name: 'authority', }), ], name: 'instructionA', }), instructionNode({ accounts: [ instructionAccountNode({ defaultValue: pdaValueNode( pdaNode({ name: 'authority', seeds: [constantPdaSeedNodeFromBytes('base58', 'AAAA')], }), [], ), isSigner: false, isWritable: false, name: 'authority', }), ], name: 'instructionB', }), ]); const result = extractPdasFromProgram(program); expect(result.pdas).toHaveLength(2); expect(result.pdas[0].name).toBe('authority'); expect(result.pdas[1].name).toBe('instructionBAuthority'); expect(warnSpy).toHaveBeenCalledOnce(); warnSpy.mockRestore(); }); test('it excludes foreign-program PDAs', () => { const program = makeProgram([ instructionNode({ accounts: [ instructionAccountNode({ defaultValue: pdaValueNode( pdaNode({ name: 'ata', programId: 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL', seeds: [constantPdaSeedNodeFromBytes('base58', 'F9bS')], }), [], ), isSigner: false, isWritable: false, name: 'ata', }), ], name: 'myInstruction', }), ]); const result = extractPdasFromProgram(program); expect(result.pdas).toEqual([]); // Account is unchanged (still inline pdaNode). expect(result.instructions[0].accounts[0].defaultValue).toEqual( pdaValueNode( pdaNode({ name: 'ata', programId: 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL', seeds: [constantPdaSeedNodeFromBytes('base58', 'F9bS')], }), [], ), ); // Nothing changed on the node at all. expect(result).toEqual(program); }); test('it keeps dynamic programId on pdaValueNode, not on PdaNode', () => { const program = makeProgram([ instructionNode({ accounts: [ instructionAccountNode({ defaultValue: pdaValueNode( pdaNode({ name: 'dynamicPda', seeds: [variablePdaSeedNode('owner', publicKeyTypeNode())], }), [pdaSeedValueNode('owner', accountValueNode('owner'))], accountValueNode('tokenProgram'), ), isSigner: false, isWritable: false, name: 'dynamicPda', }), instructionAccountNode({ isSigner: false, isWritable: false, name: 'owner' }), instructionAccountNode({ isSigner: false, isWritable: false, name: 'tokenProgram' }), ], name: 'myInstruction', }), ]); const result = extractPdasFromProgram(program); // PdaNode has no programId. expect(result.pdas[0].programId).toBeUndefined(); // pdaValueNode still has the dynamic programId. const defaultValue = result.instructions[0].accounts[0].defaultValue; expect(defaultValue).toEqual( pdaValueNode( pdaLinkNode('dynamicPda'), [pdaSeedValueNode('owner', accountValueNode('owner'))], accountValueNode('tokenProgram'), ), ); }); test('it deduplicates same seeds with different account names using first name', () => { const seeds = [constantPdaSeedNodeFromBytes('base58', 'F9bS'), variablePdaSeedNode('owner', publicKeyTypeNode())]; const program = makeProgram([ instructionNode({ accounts: [ instructionAccountNode({ defaultValue: pdaValueNode(pdaNode({ name: 'authority', seeds }), [ pdaSeedValueNode('owner', accountValueNode('owner')), ]), isSigner: false, isWritable: false, name: 'authority', }), instructionAccountNode({ isSigner: false, isWritable: false, name: 'owner' }), ], name: 'instructionA', }), instructionNode({ accounts: [ instructionAccountNode({ defaultValue: pdaValueNode(pdaNode({ name: 'admin', seeds }), [ pdaSeedValueNode('owner', accountValueNode('owner')), ]), isSigner: false, isWritable: false, name: 'admin', }), instructionAccountNode({ isSigner: false, isWritable: false, name: 'owner' }), ], name: 'instructionB', }), ]); const result = extractPdasFromProgram(program); expect(result.pdas).toHaveLength(1); expect(result.pdas[0].name).toBe('authority'); // Both instructions link to the first-encountered name. expect(result.instructions[0].accounts[0].defaultValue).toEqual( pdaValueNode(pdaLinkNode('authority'), [pdaSeedValueNode('owner', accountValueNode('owner'))]), ); expect(result.instructions[1].accounts[0].defaultValue).toEqual( pdaValueNode(pdaLinkNode('authority'), [pdaSeedValueNode('owner', accountValueNode('owner'))]), ); }); test('it preserves existing program-level PDAs', () => { const existingPda = pdaNode({ name: 'existingPda', seeds: [constantPdaSeedNodeFromBytes('base58', 'ZZZZ')], }); const program = programNode({ instructions: [ instructionNode({ accounts: [ instructionAccountNode({ defaultValue: pdaValueNode( pdaNode({ name: 'newPda', seeds: [constantPdaSeedNodeFromBytes('base58', 'F9bS')] }), [], ), isSigner: false, isWritable: false, name: 'newPda', }), ], name: 'myInstruction', }), ], name: 'testProgram', pdas: [existingPda], publicKey: '1111', }); const result = extractPdasFromProgram(program); expect(result.pdas).toHaveLength(2); expect(result.pdas[0]).toEqual(existingPda); expect(result.pdas[1].name).toBe('newPda'); }); test('it returns empty pdas when no PDA accounts exist', () => { const program = makeProgram([ instructionNode({ accounts: [ instructionAccountNode({ isSigner: false, isWritable: false, name: 'owner' }), instructionAccountNode({ isSigner: false, isWritable: false, name: 'payer' }), ], name: 'myInstruction', }), ]); const result = extractPdasFromProgram(program); expect(result.pdas).toEqual([]); // Nothing changed on the node at all. expect(result).toEqual(program); }); ================================================ FILE: packages/nodes-from-anchor/test/v01/pdaSeedNode.test.ts ================================================ import { accountValueNode, argumentValueNode, constantPdaSeedNodeFromBytes, instructionArgumentNode, numberTypeNode, pdaSeedValueNode, publicKeyTypeNode, sizePrefixTypeNode, stringTypeNode, variablePdaSeedNode, } from '@codama/nodes'; import { expect, test } from 'vitest'; import { pdaSeedNodeFromAnchorV01 } from '../../src'; test('it creates a PdaSeedNode from a const Anchor seed', () => { const nodes = pdaSeedNodeFromAnchorV01({ kind: 'const', value: [11, 57, 246, 240] }, []); expect(nodes.definition).toEqual(constantPdaSeedNodeFromBytes('base58', 'HeLLo')); expect(nodes.value).toBeUndefined(); }); test('it creates a PdaSeedNode from an account Anchor seed', () => { const nodes = pdaSeedNodeFromAnchorV01({ kind: 'account', path: 'authority' }, []); expect(nodes.definition).toEqual(variablePdaSeedNode('authority', publicKeyTypeNode())); expect(nodes.value).toEqual(pdaSeedValueNode('authority', accountValueNode('authority'))); }); test('it creates a PdaSeedNode from an arg Anchor seed', () => { const nodes = pdaSeedNodeFromAnchorV01({ kind: 'arg', path: 'capacity' }, [ instructionArgumentNode({ name: 'capacity', type: numberTypeNode('u64') }), ]); expect(nodes.definition).toEqual(variablePdaSeedNode('capacity', numberTypeNode('u64'))); expect(nodes.value).toEqual(pdaSeedValueNode('capacity', argumentValueNode('capacity'))); }); test('it removes the string prefix from arg Anchor seeds', () => { const nodes = pdaSeedNodeFromAnchorV01({ kind: 'arg', path: 'identifier' }, [ instructionArgumentNode({ name: 'identifier', type: sizePrefixTypeNode(stringTypeNode('utf8'), numberTypeNode('u32')), }), ]); expect(nodes.definition).toEqual(variablePdaSeedNode('identifier', stringTypeNode('utf8'))); expect(nodes.value).toEqual(pdaSeedValueNode('identifier', argumentValueNode('identifier'))); }); ================================================ FILE: packages/nodes-from-anchor/test/v01/typeNodes/ArrayTypeNode.test.ts ================================================ import { arrayTypeNode, fixedCountNode, numberTypeNode, prefixedCountNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { GenericsV01, typeNodeFromAnchorV01 } from '../../../src'; const generics = {} as GenericsV01; test('it creates array type nodes', () => { expect(typeNodeFromAnchorV01({ array: ['u8', 2] }, generics)).toEqual( arrayTypeNode(numberTypeNode('u8'), fixedCountNode(2)), ); expect(typeNodeFromAnchorV01({ vec: 'u8' }, generics)).toEqual( arrayTypeNode(numberTypeNode('u8'), prefixedCountNode(numberTypeNode('u32'))), ); }); test('it unwraps array nodes with generic sizes', () => { expect( typeNodeFromAnchorV01( { array: ['u8', { generic: 'N' }] }, { constArgs: { N: { kind: 'const', name: 'N', type: 'usize', value: '100' } }, typeArgs: {}, types: {}, }, ), ).toEqual(arrayTypeNode(numberTypeNode('u8'), fixedCountNode(100))); }); ================================================ FILE: packages/nodes-from-anchor/test/v01/typeNodes/BooleanTypeNode.test.ts ================================================ import { booleanTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { GenericsV01, typeNodeFromAnchorV01 } from '../../../src'; const generics = {} as GenericsV01; test('it creates boolean type nodes', () => { expect(typeNodeFromAnchorV01('bool', generics)).toEqual(booleanTypeNode()); }); ================================================ FILE: packages/nodes-from-anchor/test/v01/typeNodes/BytesTypeNode.test.ts ================================================ import { bytesTypeNode, numberTypeNode, sizePrefixTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { GenericsV01, typeNodeFromAnchorV01 } from '../../../src'; const generics = {} as GenericsV01; test('it creates bytes type nodes', () => { expect(typeNodeFromAnchorV01('bytes', generics)).toEqual( sizePrefixTypeNode(bytesTypeNode(), numberTypeNode('u32')), ); }); ================================================ FILE: packages/nodes-from-anchor/test/v01/typeNodes/EnumTypeNode.test.ts ================================================ import { booleanTypeNode, enumEmptyVariantTypeNode, enumStructVariantTypeNode, enumTupleVariantTypeNode, enumTypeNode, numberTypeNode, structFieldTypeNode, structTypeNode, tupleTypeNode, } from '@codama/nodes'; import { expect, test } from 'vitest'; import { GenericsV01, typeNodeFromAnchorV01 } from '../../../src'; const generics = {} as GenericsV01; test('it creates enum type nodes', () => { const node = typeNodeFromAnchorV01( { kind: 'enum', variants: [ { name: 'variantA' }, // Empty variant. { fields: ['u16', 'bool'], name: 'variantB' }, // Tuple variant. { fields: [{ name: 'age', type: 'u8' }], name: 'variantC' }, // Struct variant. ], }, generics, ); expect(node).toEqual( enumTypeNode([ enumEmptyVariantTypeNode('variantA'), enumTupleVariantTypeNode('variantB', tupleTypeNode([numberTypeNode('u16'), booleanTypeNode()])), enumStructVariantTypeNode( 'variantC', structTypeNode([structFieldTypeNode({ name: 'age', type: numberTypeNode('u8') })]), ), ]), ); }); ================================================ FILE: packages/nodes-from-anchor/test/v01/typeNodes/NumberTypeNode.test.ts ================================================ import { numberTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { GenericsV01, typeNodeFromAnchorV01 } from '../../../src'; const generics = {} as GenericsV01; test('it creates number type nodes', () => { expect(typeNodeFromAnchorV01('f32', generics)).toEqual(numberTypeNode('f32')); expect(typeNodeFromAnchorV01('f64', generics)).toEqual(numberTypeNode('f64')); expect(typeNodeFromAnchorV01('i8', generics)).toEqual(numberTypeNode('i8')); expect(typeNodeFromAnchorV01('i16', generics)).toEqual(numberTypeNode('i16')); expect(typeNodeFromAnchorV01('i32', generics)).toEqual(numberTypeNode('i32')); expect(typeNodeFromAnchorV01('i64', generics)).toEqual(numberTypeNode('i64')); expect(typeNodeFromAnchorV01('i128', generics)).toEqual(numberTypeNode('i128')); expect(typeNodeFromAnchorV01('shortU16', generics)).toEqual(numberTypeNode('shortU16')); expect(typeNodeFromAnchorV01('u8', generics)).toEqual(numberTypeNode('u8')); expect(typeNodeFromAnchorV01('u16', generics)).toEqual(numberTypeNode('u16')); expect(typeNodeFromAnchorV01('u32', generics)).toEqual(numberTypeNode('u32')); expect(typeNodeFromAnchorV01('u64', generics)).toEqual(numberTypeNode('u64')); expect(typeNodeFromAnchorV01('u128', generics)).toEqual(numberTypeNode('u128')); }); ================================================ FILE: packages/nodes-from-anchor/test/v01/typeNodes/OptionTypeNode.test.ts ================================================ import { numberTypeNode, optionTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { GenericsV01, typeNodeFromAnchorV01 } from '../../../src'; const generics = {} as GenericsV01; test('it creates option type nodes', () => { expect(typeNodeFromAnchorV01({ option: 'u8' }, generics)).toEqual(optionTypeNode(numberTypeNode('u8'))); }); test('it creates option type nodes with fixed size', () => { expect(typeNodeFromAnchorV01({ coption: 'u8' }, generics)).toEqual( optionTypeNode(numberTypeNode('u8'), { fixed: true, prefix: numberTypeNode('u32') }), ); expect(typeNodeFromAnchorV01({ coption: 'u8' }, generics)).toEqual( optionTypeNode(numberTypeNode('u8'), { fixed: true, prefix: numberTypeNode('u32') }), ); }); ================================================ FILE: packages/nodes-from-anchor/test/v01/typeNodes/PublicKeyTypeNode.test.ts ================================================ import { publicKeyTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { GenericsV01, typeNodeFromAnchorV01 } from '../../../src'; const generics = {} as GenericsV01; test('it creates public key type nodes', () => { expect(typeNodeFromAnchorV01('pubkey', generics)).toEqual(publicKeyTypeNode()); }); ================================================ FILE: packages/nodes-from-anchor/test/v01/typeNodes/StringTypeNode.test.ts ================================================ import { numberTypeNode, sizePrefixTypeNode, stringTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { GenericsV01, typeNodeFromAnchorV01 } from '../../../src'; const generics = {} as GenericsV01; test('it creates string type nodes', () => { expect(typeNodeFromAnchorV01('string', generics)).toEqual( sizePrefixTypeNode(stringTypeNode('utf8'), numberTypeNode('u32')), ); }); ================================================ FILE: packages/nodes-from-anchor/test/v01/typeNodes/StructTypeNode.test.ts ================================================ import { CODAMA_ERROR__ANCHOR__UNRECOGNIZED_IDL_TYPE, CodamaError } from '@codama/errors'; import { arrayTypeNode, numberTypeNode, prefixedCountNode, publicKeyTypeNode, sizePrefixTypeNode, stringTypeNode, structFieldTypeNode, structTypeNode, tupleTypeNode, } from '@codama/nodes'; import { expect, test } from 'vitest'; import { GenericsV01, typeNodeFromAnchorV01 } from '../../../src'; const generics = {} as GenericsV01; test('it creates struct type nodes', () => { const node = typeNodeFromAnchorV01( { fields: [ { name: 'name', type: 'string' }, { name: 'age', type: 'u8' }, { name: 'created_at', type: 'u8' }, ], kind: 'struct', }, generics, ); expect(node).toEqual( structTypeNode([ structFieldTypeNode({ name: 'name', type: sizePrefixTypeNode(stringTypeNode('utf8'), numberTypeNode('u32')), }), structFieldTypeNode({ name: 'age', type: numberTypeNode('u8') }), structFieldTypeNode({ name: 'createdAt', type: numberTypeNode('u8') }), ]), ); }); test('it creates tuple type nodes when unnamed fields are provided', () => { const node = typeNodeFromAnchorV01( { fields: ['u8', { vec: 'pubkey' }], kind: 'struct', }, generics, ); expect(node).toEqual( tupleTypeNode([ numberTypeNode('u8'), arrayTypeNode(publicKeyTypeNode(), prefixedCountNode(numberTypeNode('u32'))), ]), ); }); test('it fails when a mixture of named and unnamed fields are provided', () => { const anchorIdl = { fields: [{ name: 'name', type: 'string' }, 'u8'], kind: 'struct', } as const; // @ts-expect-error Invalid IDL type because of mixed named and unnamed fields. expect(() => typeNodeFromAnchorV01(anchorIdl)).toThrow( new CodamaError(CODAMA_ERROR__ANCHOR__UNRECOGNIZED_IDL_TYPE, { idlType: JSON.stringify(anchorIdl), }), ); }); ================================================ FILE: packages/nodes-from-anchor/test/v01/typeNodes/TupleTypeNode.test.ts ================================================ import { numberTypeNode, publicKeyTypeNode, tupleTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { GenericsV01, typeNodeFromAnchorV01 } from '../../../src'; const generics = {} as GenericsV01; test('it creates tuple type nodes', () => { const node = typeNodeFromAnchorV01( { fields: ['u8', 'pubkey'], kind: 'struct', }, generics, ); expect(node).toEqual(tupleTypeNode([numberTypeNode('u8'), publicKeyTypeNode()])); }); ================================================ FILE: packages/nodes-from-anchor/tsconfig.declarations.json ================================================ { "compilerOptions": { "declaration": true, "declarationMap": true, "emitDeclarationOnly": true, "outDir": "./dist/types" }, "extends": "./tsconfig.json", "include": ["src/index.ts", "src/types"] } ================================================ FILE: packages/nodes-from-anchor/tsconfig.json ================================================ { "$schema": "https://json.schemastore.org/tsconfig", "compilerOptions": { "lib": [] }, "display": "@codama/nodes-from-anchor", "extends": "../../tsconfig.json", "include": ["src", "test"] } ================================================ FILE: packages/nodes-from-anchor/tsup.config.ts ================================================ import { defineConfig } from 'tsup'; import { getPackageBuildConfigs } from '../../tsup.config.base'; export default defineConfig(getPackageBuildConfigs()); ================================================ FILE: packages/nodes-from-anchor/vitest.config.mts ================================================ import { defineConfig } from 'vitest/config'; import { getVitestConfig } from '../../vitest.config.base.mjs'; export default defineConfig({ test: { projects: [getVitestConfig('browser'), getVitestConfig('node'), getVitestConfig('react-native')], }, }); ================================================ FILE: packages/renderers-core/.gitignore ================================================ dist/ ================================================ FILE: packages/renderers-core/.prettierignore ================================================ dist/ test/e2e/ test-ledger/ target/ CHANGELOG.md ================================================ FILE: packages/renderers-core/LICENSE ================================================ MIT License Copyright (c) 2025 Codama Copyright (c) 2024 Metaplex Foundation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: packages/renderers-core/README.md ================================================ # Codama ➤ Renderers ➤ Core [![npm][npm-image]][npm-url] [![npm-downloads][npm-downloads-image]][npm-url] [npm-downloads-image]: https://img.shields.io/npm/dm/@codama/renderers-core.svg?style=flat [npm-image]: https://img.shields.io/npm/v/@codama/renderers-core.svg?style=flat&label=%40codama%2Frenderers-core [npm-url]: https://www.npmjs.com/package/@codama/renderers-core This package provides the core utility for generating clients from Codama IDLs. Its aim is mainly to provide helpers for other renderer packages such as [`@codama/renderers-js`](https://github.com/codama-idl/renderers-js) and [`@codama/renderers-rust`](https://github.com/codama-idl/renderers-rust). ## Installation ```sh pnpm install @codama/renderers-core ``` > [!NOTE] > This package is **not** included in the main [`codama`](../library) package. ## Filesystem wrappers This package offers several helper functions that delegate to the native Filesystem API — i.e. `node:fs` — when using the Node.js runtime. However, in any other environment — such as the browser — these functions will throw a `CODAMA_ERROR__NODE_FILESYSTEM_FUNCTION_UNAVAILABLE` error as a Filesystem API is not available. This enables us to import renderers regardless of the runtime environment. ### `createDirectory` Creates a directory at the given path, recursively. ```ts createDirectory(newDirectoryPath); ``` ### `deleteDirectory` Deletes a directory, recursively, if it exists. ```ts deleteDirectory(directoryPath); ``` ### `writeFile` Creates a new file at the given path with the given content. Creates its parent directory, recursively, if it does not exist. ```ts writeFile(filePath, content); ``` ### `readFile` Reads the UTF-8 content of a file as a string. ```ts const content = readFile(filePath); ``` ### `readJson` Reads the UTF-8 content of a file as a JSON object. ```ts const json = readJson(filePath); ``` ## Path wrappers This package also offers several `path` helpers that delegate to the native `node:path` module when using the Node.js runtime but provide a fallback implementation when using any other runtime. ### `joinPath` Joins multiple path segments into a single path. ```ts const path = joinPath('path', 'to', 'my', 'file.ts'); ``` ### `pathDirectory` Returns the parent directory of a given path. ```ts const parentPath = pathDirectory(path); ``` ## Fragments The concept of fragments is commonly used in Codama renderers as a way to combine a piece of code with any context that is relevant to that piece of code. For instance, a fragment may include a dependency map that lists all the module imports required by that piece of code. Since fragments vary from one renderer to another, this package cannot provide a one-size-fits-all `Fragment` type. Instead, it provides some base types and utility functions that can be used to build more specific fragment types. ### `BaseFragment` The `BaseFragment` type is an object that includes a `content` string. Renderers may extend this type to include any additional context they need. ```ts type Fragment = BaseFragment & Readonly<{ importMap: ImportMap }>; ``` ### `mapFragmentContent` The `mapFragmentContent` helper can be used to transform the `content` of a fragment while preserving the rest of its context. ```ts const updatedFragment = mapFragmentContent(fragment, c => `/** This is a fragment. */\n${c}`); ``` ### `mapFragmentContentAsync` The `mapFragmentContentAsync` helper can be used to transform the `content` of a fragment asynchronously while preserving the rest of its context. ```ts const updatedFragment = mapFragmentContentAsync(fragment, async c => `${await getDocs(c)}\n${c}`); ``` ### `setFragmentContent` The `setFragmentContent` helper can be used to replace the `content` of a fragment while preserving the rest of its context. ```ts const updatedFragment = setFragmentContent(fragment, '[redacted]'); ``` ### `createFragmentTemplate` The `createFragmentTemplate` helper can be used to create [tagged template literal](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates) functions. For this, you need to provide a function that can merge multiple fragments together and a function that can identify fragments from other values. ```ts function fragment(template: TemplateStringsArray, ...items: unknown[]): Fragment { return createFragmentTemplate(template, items, isFragment, mergeFragments); } const apple = fragment`apple`; const banana = fragment`banana`; const fruits = fragment`${apple}, ${banana}`; ``` ## Render maps This package also provides a `RenderMap` type and a handful of helpers to work with it. A `RenderMap` is a utility type that helps manage a collection of `Fragment` files to be rendered. It acts as a middleman between the logic that generates the content and the logic that writes the content to the filesystem. As such, it provides a way to access the generated content outside an environment that supports the Filesystem API — such as the browser. It also helps us write tests about the generated code without having to write it to the filesystem. ### Creating new `RenderMaps` You can use the `createRenderMap` function with no arguments to create a new empty `RenderMap`. ```ts const renderMap = createRenderMap(); ``` Since `RenderMaps` store fragments, you may specify a custom fragment type parameter that extends `BaseFragment` when creating a new `RenderMap`. ```ts type Fragment = BaseFragment & { imports: ImportMap }; const renderMap = createRenderMap(); ``` You may provide the path and fragment of a file to create a `RenderMap` with a single file. ```ts const renderMap = createRenderMap('path/to/file.ts', { content: 'file content' }); ``` You may also provide an object mapping file paths to their fragments to create a `RenderMap` with multiple files. ```ts const renderMap = createRenderMap({ 'path/to/file.ts': { content: 'file content' }, 'path/to/another/file.ts': { content: 'another file content' }, }); ``` Note that when setting paths inside a `RenderMap`, they should be relative to the base directory that will be provided when writing the `RenderMap` to the filesystem. For instance, if we decide to use `src/generated` as the base directory when writing the `RenderMap`, then using a path such as `accounts/mint.ts` will result in the file being written to `src/generated/accounts/mint.ts`. ### Adding content to a `RenderMap` To add content to a `RenderMap`, you may use the `addToRenderMap` function by providing the path and the fragment of the file to be added. Note that, here as well, the path should be relative to the base directory that will be provided when writing the `RenderMap` to the filesystem. ```ts const updatedRenderMap = addToRenderMap(renderMap, 'path/to/file.ts', { content: 'file content' }); ``` Since `RenderMaps` are immutable, you may want to use the `pipe` function from `@codama/visitors-core` — also available in `codama` — to chain multiple updates together. ```ts const renderMap = pipe( createRenderMap(), m => addToRenderMap(m, 'programs/token.ts', { content: 'export type TokenProgram = {...}' }), m => addToRenderMap(m, 'accounts/mint.ts', { content: 'export type MintAccount = {...}' }), m => addToRenderMap(m, 'instructions/transfer.ts', { content: 'export function getTransferInstruction() {...}' }), ); ``` ### Merging multiple `RenderMaps` You may use the `mergeRenderMaps` helper to combine multiple `RenderMap` instances into a single one. If two `RenderMap` instances contain the same file path, the content from the latter will overwrite the content from the former. ```ts const renderMapA = createRenderMap('programs/programA.ts', { content: 'export type ProgramA = {...}' }); const renderMapB = createRenderMap('programs/programB.ts', { content: 'export type ProgramB = {...}' }); const mergedRenderMap = mergeRenderMaps(renderMapA, renderMapB); ``` ### Removing content from a `RenderMap` To remove files from a `RenderMap`, simply use the `removeFromRenderMap` function by providing the relative path of the file to be removed. ```ts const updatedRenderMap = removeFromRenderMap(renderMap, 'programs/token.ts'); ``` ### Accessing content from a `RenderMap` The `RenderMap` type is essentially a JavaScript `Map` so you can use all the methods available on the `Map` prototype. Therefore, you may use the `get` method to access the content of a file from its relative path. ```ts const content: string | undefined = renderMap.get('programs/token.ts'); ``` However, this may return `undefined` if the file does not exist on the `RenderMap`. If you want to access the content of a file and throw an error if it does not exist, you can use the `getFromRenderMap` helper instead. ```ts const content: string = getFromRenderMap(renderMap, 'programs/token.ts'); ``` You may also use the `renderMapContains` helper to check if the provided file content exists in the `RenderMap` at the given path. The expected file content can be a string or a regular expression. ```ts const hasTokenProgram = renderMapContains(renderMap, 'programs/token.ts', 'export type TokenProgram = {...}'); const hasMintAccount = renderMapContains(renderMap, 'programs/token.ts', /MintAccount/); ``` ### Transforming content from a `RenderMap` To map the content of all files inside a `RenderMap`, you can use the `mapRenderMapContent` function. This method accepts a function that takes the content of a file and returns a new content. ```ts const updatedRenderMap = mapRenderMapContent(renderMap, c => `/** Prefix for all files */\n\n${c}`); ``` An asynchronous version of this function called `mapRenderMapContentAsync` is also available in case the transformation function needs to be asynchronous. ```ts const updatedRenderMap = await mapRenderMapContentAsync(renderMap, async content => { const transformedContent = await someAsyncFunction(content); return `/** Prefix for all files */\n\n${transformedContent}`; }); ``` Note that in both cases, a second argument is available in the mapping function that provides the relative path of the file being transformed. ```ts const updatedRenderMap = mapRenderMapContent(renderMap, (content, path) => `/** File: ${path} */\n\n${content}`); ``` ### Writing a `RenderMap` to the filesystem When the `RenderMap` is ready to be written to the filesystem, you can use the `writeRenderMap` helper by providing the base directory where all files should be written. All paths inside the `RenderMap` will be appended to this base directory. ```ts const renderMap = createRenderMap({ 'programs/token.ts': { content: 'export type TokenProgram = {...}' }, 'accounts/mint.ts': { content: 'export type MintAccount = {...}' }, }); writeRenderMap(renderMap, 'src/generated'); // In this example, files will be written to: // - src/generated/programs/token.ts // - src/generated/accounts/mint.ts. ``` ### Using visitors When building renderers, you will most likely create a visitor that traverses the Codama IDL and returns a `RenderMap`. That way, you can test the generated content without having to write it to the filesystem. For instance, the [`@codama/renderers-js`](https://github.com/codama-idl/renderers-js) package exports a `getRenderMapVisitor` function that does just that. ```ts import { getRenderMapVisitor } from '@codama/renderers-js'; const renderMap = codama.accept(getRenderMapVisitor()); ``` If you have access to a visitor that returns a `RenderMap` — also described as `Visitor` — then, you can wrap it inside the `writeRenderMapVisitor` to directly write the content to the filesystem at the given base directory. ```ts import { getRenderMapVisitor } from '@codama/renderers-js'; codama.accept(writeRenderMapVisitor(getRenderMapVisitor(), 'src/generated')); ``` Note however that, if you are writing your own renderer, you should probably offer a higher-level visitor that includes this logic and also does some additional work such as deleting the base directory before writing the new content if it already exists. For instance, the recommended way of using the `@codama/renderers-js` package is to use its default exported visitor which does exactly that. ```ts import renderVisitor from '@codama/renderers-js'; codama.accept(renderVisitor('src/generated')); ``` Here's a simple example of how to set up the basis of a renderer from an existing `getRenderMapVisitor`. ```ts import { deleteDirectory } from '@codama/renderers-core'; import { rootNodeVisitor, visit } from '@codama/visitors-core'; type RenderOptions = { deleteFolderBeforeRendering?: boolean; // Any other options... }; export function renderVisitor(path: string, options: RenderOptions = {}) { return rootNodeVisitor(async root => { // Delete existing generated folder. if (options.deleteFolderBeforeRendering ?? true) { deleteDirectory(path); } // Render the new files. visit(root, writeRenderMapVisitor(getRenderMapVisitor(options), path)); }); } ``` ================================================ FILE: packages/renderers-core/package.json ================================================ { "name": "@codama/renderers-core", "version": "1.3.7", "description": "Core types and helpers for Codama renderers to use", "exports": { "types": "./dist/types/index.d.ts", "react-native": "./dist/index.react-native.mjs", "browser": { "import": "./dist/index.browser.mjs", "require": "./dist/index.browser.cjs" }, "node": { "import": "./dist/index.node.mjs", "require": "./dist/index.node.cjs" } }, "browser": { "./dist/index.node.cjs": "./dist/index.browser.cjs", "./dist/index.node.mjs": "./dist/index.browser.mjs" }, "main": "./dist/index.node.cjs", "module": "./dist/index.node.mjs", "react-native": "./dist/index.react-native.mjs", "types": "./dist/types/index.d.ts", "type": "commonjs", "files": [ "./dist/types", "./dist/index.*" ], "sideEffects": false, "keywords": [ "solana", "framework", "standard", "visitors" ], "scripts": { "build": "rimraf dist && tsup && tsc -p ./tsconfig.declarations.json", "dev": "vitest --project node", "lint": "eslint . && prettier --check .", "lint:fix": "eslint --fix . && prettier --write .", "test": "pnpm test:types && pnpm test:treeshakability && pnpm test:unit", "test:treeshakability": "for file in dist/index.*.mjs; do agadoo $file; done", "test:types": "tsc --noEmit", "test:unit": "vitest run" }, "dependencies": { "@codama/errors": "workspace:*", "@codama/nodes": "workspace:*", "@codama/visitors-core": "workspace:*" }, "license": "MIT", "repository": { "type": "git", "url": "https://github.com/codama-idl/codama" }, "bugs": { "url": "http://github.com/codama-idl/codama/issues" }, "browserslist": [ "supports bigint and not dead", "maintained node versions" ] } ================================================ FILE: packages/renderers-core/src/fragment.ts ================================================ export type BaseFragment = Readonly<{ content: string }>; export function mapFragmentContent( fragment: TFragment, mapContent: (content: string) => string, ): TFragment { return setFragmentContent(fragment, mapContent(fragment.content)); } export async function mapFragmentContentAsync( fragment: TFragment, mapContent: (content: string) => Promise, ): Promise { return setFragmentContent(fragment, await mapContent(fragment.content)); } export function setFragmentContent(fragment: TFragment, content: string): TFragment { return Object.freeze({ ...fragment, content }); } export function createFragmentTemplate( template: TemplateStringsArray, items: unknown[], isFragment: (value: unknown) => value is TFragment, mergeFragments: (fragments: TFragment[], mergeContent: (contents: string[]) => string) => TFragment, ): TFragment { const fragments = items.filter(isFragment); const zippedItems = items.map((item, i) => { const itemPrefix = template[i]; if (typeof item === 'undefined') return itemPrefix; if (isFragment(item)) return itemPrefix + item.content; return itemPrefix + String(item as string); }); return mergeFragments(fragments, () => zippedItems.join('') + template[template.length - 1]); } ================================================ FILE: packages/renderers-core/src/fs.ts ================================================ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; import { CODAMA_ERROR__NODE_FILESYSTEM_FUNCTION_UNAVAILABLE, CodamaError } from '@codama/errors'; import { Path, pathDirectory } from './path'; export function createDirectory(path: Path): void { if (!__NODEJS__) { throw new CodamaError(CODAMA_ERROR__NODE_FILESYSTEM_FUNCTION_UNAVAILABLE, { fsFunction: 'mkdirSync' }); } mkdirSync(path, { recursive: true }); } export function deleteDirectory(path: Path): void { if (!__NODEJS__) { throw new CodamaError(CODAMA_ERROR__NODE_FILESYSTEM_FUNCTION_UNAVAILABLE, { fsFunction: 'rmSync' }); } if (existsSync(path)) { rmSync(path, { recursive: true }); } } export function writeFile(path: Path, content: string): void { if (!__NODEJS__) { throw new CodamaError(CODAMA_ERROR__NODE_FILESYSTEM_FUNCTION_UNAVAILABLE, { fsFunction: 'writeFileSync' }); } const directory = pathDirectory(path); if (!existsSync(directory)) { createDirectory(directory); } writeFileSync(path, content); } export function fileExists(path: Path): boolean { if (!__NODEJS__) { throw new CodamaError(CODAMA_ERROR__NODE_FILESYSTEM_FUNCTION_UNAVAILABLE, { fsFunction: 'existsSync' }); } return existsSync(path); } export function readFile(path: Path): string { if (!__NODEJS__) { throw new CodamaError(CODAMA_ERROR__NODE_FILESYSTEM_FUNCTION_UNAVAILABLE, { fsFunction: 'readFileSync' }); } return readFileSync(path, 'utf-8'); } export function readJson(path: Path): T { return JSON.parse(readFile(path)) as T; } ================================================ FILE: packages/renderers-core/src/index.ts ================================================ export * from './fragment'; export * from './fs'; export * from './path'; export * from './renderMap'; ================================================ FILE: packages/renderers-core/src/path.ts ================================================ import { dirname, join } from 'node:path'; export type Path = string; export function joinPath(...paths: Path[]): string { if (!__NODEJS__) { return paths.join('/').replace(/\/+/g, '/'); } return join(...paths); } export function pathDirectory(path: Path): Path { if (!__NODEJS__) { return path.substring(0, path.lastIndexOf('/')); } return dirname(path); } ================================================ FILE: packages/renderers-core/src/renderMap.ts ================================================ import { CODAMA_ERROR__VISITORS__RENDER_MAP_KEY_NOT_FOUND, CodamaError } from '@codama/errors'; import { NodeKind } from '@codama/nodes'; import { mapVisitor, Visitor } from '@codama/visitors-core'; import { BaseFragment, mapFragmentContent, mapFragmentContentAsync } from './fragment'; import { writeFile } from './fs'; import { joinPath, Path } from './path'; export type RenderMap = ReadonlyMap; export function createRenderMap(): RenderMap; export function createRenderMap(path: Path, content: TFragment): RenderMap; export function createRenderMap( entries: Record, ): RenderMap; export function createRenderMap( pathOrEntries?: Path | Record, content?: TFragment, ): RenderMap { let entries: [Path, TFragment][] = []; if (typeof pathOrEntries === 'string' && pathOrEntries !== undefined && content !== undefined) { entries = [[pathOrEntries, content]]; } else if (typeof pathOrEntries === 'object' && pathOrEntries !== null) { entries = Object.entries(pathOrEntries).flatMap(([key, value]) => value === undefined ? [] : ([[key, value]] as const), ); } return Object.freeze(new Map(entries)); } export function addToRenderMap( renderMap: RenderMap, path: Path, content: TFragment, ): RenderMap { return mergeRenderMaps([renderMap, createRenderMap(path, content)]); } export function removeFromRenderMap( renderMap: RenderMap, path: Path, ): RenderMap { const newMap = new Map(renderMap); newMap.delete(path); return Object.freeze(newMap); } export function mergeRenderMaps( renderMaps: RenderMap[], ): RenderMap { if (renderMaps.length === 0) return createRenderMap(); if (renderMaps.length === 1) return renderMaps[0]; const merged = new Map(renderMaps[0]); for (const map of renderMaps.slice(1)) { for (const [key, value] of map) { merged.set(key, value); } } return Object.freeze(merged); } export function mapRenderMapFragment( renderMap: RenderMap, fn: (fragment: TFragment, path: Path) => TFragment, ): RenderMap { return Object.freeze(new Map([...[...renderMap.entries()].map(([key, value]) => [key, fn(value, key)] as const)])); } export async function mapRenderMapFragmentAsync( renderMap: RenderMap, fn: (fragment: TFragment, path: Path) => Promise, ): Promise> { return Object.freeze( new Map( await Promise.all([ ...[...renderMap.entries()].map(async ([key, value]) => [key, await fn(value, key)] as const), ]), ), ); } export function mapRenderMapContent( renderMap: RenderMap, fn: (content: string, path: Path) => string, ): RenderMap { return mapRenderMapFragment(renderMap, (fragment, path) => mapFragmentContent(fragment, content => fn(content, path)), ); } export async function mapRenderMapContentAsync( renderMap: RenderMap, fn: (content: string, path: Path) => Promise, ): Promise> { return await mapRenderMapFragmentAsync(renderMap, (fragment, path) => mapFragmentContentAsync(fragment, content => fn(content, path)), ); } export function getFromRenderMap( renderMap: RenderMap, path: Path, ): TFragment { const value = renderMap.get(path); if (value === undefined) { throw new CodamaError(CODAMA_ERROR__VISITORS__RENDER_MAP_KEY_NOT_FOUND, { key: path }); } return value; } export function renderMapContains( renderMap: RenderMap, path: Path, value: RegExp | string, ): boolean { const { content } = getFromRenderMap(renderMap, path); return typeof value === 'string' ? content.includes(value) : value.test(content); } export function writeRenderMap(renderMap: RenderMap, basePath: Path): void { renderMap.forEach(({ content }, relativePath) => { writeFile(joinPath(basePath, relativePath), content); }); } export function writeRenderMapVisitor< TFragment extends BaseFragment = BaseFragment, TNodeKind extends NodeKind = NodeKind, >(visitor: Visitor, TNodeKind>, basePath: Path): Visitor { return mapVisitor(visitor, renderMap => writeRenderMap(renderMap, basePath)); } ================================================ FILE: packages/renderers-core/src/types/global.d.ts ================================================ declare const __BROWSER__: boolean; declare const __ESM__: boolean; declare const __NODEJS__: boolean; declare const __REACTNATIVE__: boolean; declare const __TEST__: boolean; declare const __VERSION__: string; ================================================ FILE: packages/renderers-core/test/fs.test.json ================================================ { "key": "value" } ================================================ FILE: packages/renderers-core/test/fs.test.ts ================================================ import { CODAMA_ERROR__NODE_FILESYSTEM_FUNCTION_UNAVAILABLE, CodamaError } from '@codama/errors'; import { expect, test } from 'vitest'; import { createDirectory, deleteDirectory, fileExists, readJson, writeFile } from '../src'; if (__NODEJS__) { test('it reads JSON objects from files', () => { const result = readJson('./test/fs.test.json'); expect(result).toEqual({ key: 'value' }); }); test('it checks if a file exists', () => { const result = fileExists('./test/fs.test.json'); expect(result).toBe(true); }); } else { test('it fails to call readJson', () => { expect(() => readJson('./path')).toThrow( new CodamaError(CODAMA_ERROR__NODE_FILESYSTEM_FUNCTION_UNAVAILABLE, { fsFunction: 'readFileSync' }), ); }); test('it fails to call fileExists', () => { expect(() => fileExists('./path')).toThrow( new CodamaError(CODAMA_ERROR__NODE_FILESYSTEM_FUNCTION_UNAVAILABLE, { fsFunction: 'existsSync' }), ); }); test('it fails to call createDirectory', () => { expect(() => createDirectory('./path')).toThrow( new CodamaError(CODAMA_ERROR__NODE_FILESYSTEM_FUNCTION_UNAVAILABLE, { fsFunction: 'mkdirSync' }), ); }); test('it fails to call deleteDirectory', () => { expect(() => deleteDirectory('./path')).toThrow( new CodamaError(CODAMA_ERROR__NODE_FILESYSTEM_FUNCTION_UNAVAILABLE, { fsFunction: 'rmSync' }), ); }); test('it fails to call writeFile', () => { expect(() => writeFile('./path', 'content')).toThrow( new CodamaError(CODAMA_ERROR__NODE_FILESYSTEM_FUNCTION_UNAVAILABLE, { fsFunction: 'writeFileSync' }), ); }); } ================================================ FILE: packages/renderers-core/test/path.test.ts ================================================ import { expect, test } from 'vitest'; import { joinPath, pathDirectory } from '../src'; test('it joins path together', () => { const result = joinPath('foo', 'bar', 'baz'); expect(result).toEqual('foo/bar/baz'); }); test('it gets the directory of a path', () => { const result = pathDirectory('foo/bar/baz'); expect(result).toEqual('foo/bar'); }); ================================================ FILE: packages/renderers-core/test/renderMap.test.ts ================================================ import { assert, describe, expect, expectTypeOf, test } from 'vitest'; import { addToRenderMap, BaseFragment, createRenderMap, mapRenderMapContent, mapRenderMapContentAsync, mergeRenderMaps, removeFromRenderMap, RenderMap, } from '../src'; describe('createRenderMap', () => { test('it creates an empty render map', () => { expect(createRenderMap()).toStrictEqual(new Map()); expectTypeOf(createRenderMap()).toEqualTypeOf>(); }); test('it creates an empty render map using a custom fragment type', () => { type CustomFragment = BaseFragment & { customProperty: number }; expect(createRenderMap()).toStrictEqual(new Map()); expectTypeOf(createRenderMap()).toEqualTypeOf>(); }); test('it creates a render map from a path and a fragment', () => { expect(createRenderMap('some/path', { content: 'Some content' })).toStrictEqual( new Map([['some/path', { content: 'Some content' }]]), ); }); test('it creates a render map from a record of entries', () => { expect( createRenderMap({ 'some/path/a': { content: 'Some content A' }, 'some/path/b': { content: 'Some content B' }, }), ).toStrictEqual( new Map([ ['some/path/a', { content: 'Some content A' }], ['some/path/b', { content: 'Some content B' }], ]), ); }); test('it removes undefined entries from the provided record', () => { expect( createRenderMap({ 'some/path': { content: 'Some content' }, 'some/path/undefined': undefined, }), ).toStrictEqual(new Map([['some/path', { content: 'Some content' }]])); }); test('it freezes the returned render map', () => { assert.isFrozen(createRenderMap()); assert.isFrozen(createRenderMap('some/path', { content: 'Some content' })); assert.isFrozen(createRenderMap({ 'some/path': { content: 'Some content' } })); }); }); describe('addToRenderMap', () => { test('it adds new entries to render map', () => { const renderMap = createRenderMap('some/path', { content: 'Some content' }); expect(addToRenderMap(renderMap, 'some/new/path', { content: 'Some new content' })).toStrictEqual( new Map([ ['some/path', { content: 'Some content' }], ['some/new/path', { content: 'Some new content' }], ]), ); }); test('it overwrites existing entries in the render map', () => { const renderMap = createRenderMap('some/path', { content: 'Some content' }); expect(addToRenderMap(renderMap, 'some/path', { content: 'Some new content' })).toStrictEqual( new Map([['some/path', { content: 'Some new content' }]]), ); }); test('it freezes the returned render map', () => { assert.isFrozen(addToRenderMap(createRenderMap(), 'some/new/path', { content: 'Some new content' })); }); }); describe('removeFromRenderMap', () => { test('it removes existing entries from a render map', () => { const renderMap = createRenderMap({ pathA: { content: 'Content A' }, pathB: { content: 'Content B' } }); expect(removeFromRenderMap(renderMap, 'pathA')).toStrictEqual(new Map([['pathB', { content: 'Content B' }]])); }); test('it can remove the last entry of a render map', () => { const renderMap = createRenderMap('pathA', { content: 'Content A' }); expect(removeFromRenderMap(renderMap, 'pathA')).toStrictEqual(new Map()); }); test('it ignores missing paths', () => { const renderMap = createRenderMap(); expect(removeFromRenderMap(renderMap, 'missingPaths')).toStrictEqual(new Map()); }); test('it freezes the returned render map', () => { assert.isFrozen(removeFromRenderMap(createRenderMap(), 'some/path')); }); }); describe('mergeRenderMaps', () => { test('it returns an empty render map when no maps are provided', () => { expect(mergeRenderMaps([])).toStrictEqual(new Map()); }); test('it returns the first render map as-is when only one map is provided', () => { const renderMap = createRenderMap('pathA', { content: 'ContentA' }); expect(mergeRenderMaps([renderMap])).toBe(renderMap); }); test('it merges the entries of two render maps', () => { expect( mergeRenderMaps([ createRenderMap('pathA', { content: 'ContentA' }), createRenderMap('pathB', { content: 'ContentB' }), ]), ).toStrictEqual( new Map([ ['pathA', { content: 'ContentA' }], ['pathB', { content: 'ContentB' }], ]), ); }); test('later entries overwrite earlier entries', () => { expect( mergeRenderMaps([ createRenderMap('samePath', { content: 'Old content' }), createRenderMap('samePath', { content: 'New content' }), ]), ).toStrictEqual(new Map([['samePath', { content: 'New content' }]])); }); test('it freezes the returned render map', () => { assert.isFrozen(mergeRenderMaps([])); assert.isFrozen(mergeRenderMaps([createRenderMap('pathA', { content: 'ContentA' })])); assert.isFrozen( mergeRenderMaps([ createRenderMap('pathA', { content: 'ContentA' }), createRenderMap('pathB', { content: 'ContentB' }), ]), ); }); }); describe('mapRenderMapContent', () => { test('it maps the content of all entries inside a render map', () => { expect( mapRenderMapContent( createRenderMap({ pathA: { content: 'ContentA' }, pathB: { content: 'ContentB' }, }), content => `Mapped: ${content}`, ), ).toStrictEqual( new Map([ ['pathA', { content: 'Mapped: ContentA' }], ['pathB', { content: 'Mapped: ContentB' }], ]), ); }); test('it provides the path of the content being mapped', () => { expect( mapRenderMapContent( createRenderMap({ pathA: { content: 'Content' }, pathB: { content: 'Content' }, }), (content, path) => `${content} from ${path}`, ), ).toStrictEqual( new Map([ ['pathA', { content: 'Content from pathA' }], ['pathB', { content: 'Content from pathB' }], ]), ); }); test('it freezes the returned render map', () => { assert.isFrozen(mapRenderMapContent(createRenderMap(), c => c)); }); }); describe('mapRenderMapContentAsync', () => { test('it maps the content of all entries inside a render map', async () => { expect( await mapRenderMapContentAsync( createRenderMap({ pathA: { content: 'ContentA' }, pathB: { content: 'ContentB' }, }), content => Promise.resolve(`Mapped: ${content}`), ), ).toStrictEqual( new Map([ ['pathA', { content: 'Mapped: ContentA' }], ['pathB', { content: 'Mapped: ContentB' }], ]), ); }); test('it provides the path of the content being mapped', async () => { expect( await mapRenderMapContentAsync( createRenderMap({ pathA: { content: 'Content' }, pathB: { content: 'Content' }, }), (content, path) => Promise.resolve(`${content} from ${path}`), ), ).toStrictEqual( new Map([ ['pathA', { content: 'Content from pathA' }], ['pathB', { content: 'Content from pathB' }], ]), ); }); test('it freezes the returned render map', async () => { assert.isFrozen(await mapRenderMapContentAsync(createRenderMap(), c => Promise.resolve(c))); }); }); ================================================ FILE: packages/renderers-core/test/types/global.d.ts ================================================ declare const __BROWSER__: boolean; declare const __ESM__: boolean; declare const __NODEJS__: boolean; declare const __REACTNATIVE__: boolean; declare const __TEST__: boolean; declare const __VERSION__: string; ================================================ FILE: packages/renderers-core/tsconfig.declarations.json ================================================ { "compilerOptions": { "declaration": true, "declarationMap": true, "emitDeclarationOnly": true, "outDir": "./dist/types" }, "extends": "./tsconfig.json", "include": ["src/index.ts", "src/types"] } ================================================ FILE: packages/renderers-core/tsconfig.json ================================================ { "$schema": "https://json.schemastore.org/tsconfig", "compilerOptions": { "lib": [] }, "display": "@codama/renderers-core", "extends": "../../tsconfig.json", "include": ["src", "test"] } ================================================ FILE: packages/renderers-core/tsup.config.ts ================================================ import { defineConfig } from 'tsup'; import { getPackageBuildConfigs } from '../../tsup.config.base'; export default defineConfig(getPackageBuildConfigs()); ================================================ FILE: packages/renderers-core/vitest.config.mts ================================================ import { defineConfig } from 'vitest/config'; import { getVitestConfig } from '../../vitest.config.base.mjs'; export default defineConfig({ test: { projects: [getVitestConfig('browser'), getVitestConfig('node'), getVitestConfig('react-native')], }, }); ================================================ FILE: packages/validators/.gitignore ================================================ dist/ ================================================ FILE: packages/validators/.prettierignore ================================================ dist/ test/e2e/ test-ledger/ target/ CHANGELOG.md ================================================ FILE: packages/validators/LICENSE ================================================ MIT License Copyright (c) 2025 Codama Copyright (c) 2024 Metaplex Foundation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: packages/validators/README.md ================================================ # Codama ➤ Validators [![npm][npm-image]][npm-url] [![npm-downloads][npm-downloads-image]][npm-url] [npm-downloads-image]: https://img.shields.io/npm/dm/@codama/validators.svg?style=flat [npm-image]: https://img.shields.io/npm/v/@codama/validators.svg?style=flat&label=%40codama%2Fvalidators [npm-url]: https://www.npmjs.com/package/@codama/validators This package offers a set of validation rules for Codama IDLs to ensure that they are correctly formatted. ## Installation ```sh pnpm install @codama/validators ``` > [!NOTE] > This package is included in the main [`codama`](../library) package. Meaning, you already have access to its content if you are installing Codama this way. > > ```sh > pnpm install codama > ``` ## Types ### `ValidationItem` A validation item describes a single piece of information — typically a warning or an error — about a node in the Codama IDL. ```ts type ValidationItem = { // The level of importance of a validation item. level: 'debug' | 'trace' | 'info' | 'warn' | 'error'; // A human-readable message describing the issue or information. message: string; // The node that the validation item is related to. node: Node; // The path of nodes that led to the node above (including the node itself). path: NodePath; }; ``` ## Functions ### `getValidationItemsVisitor(visitor)` The `getValidationItemsVisitor` function returns a visitor that collects all validation items from a Codama IDL. Note that this visitor is still a work in progress and does not cover all validation rules. ```ts import { getValidationItemsVisitor } from '@codama/validators'; const validationItems = codama.accept(getValidationItemsVisitor()); ``` ### `throwValidatorItemsVisitor(visitor)` The `throwValidatorItemsVisitor` function accepts a `Visitor` and throws an error if any validation items above a certain level are found. By default, the level is set to `'error'` but a second argument can be passed to change it. ```ts import { throwValidatorItemsVisitor, getValidationItemsVisitor } from '@codama/validators'; // Throw if any "error" items are found. codama.accept(throwValidatorItemsVisitor(getValidationItemsVisitor())); // Throw if any "warn" or "error" items are found. codama.accept(throwValidatorItemsVisitor(getValidationItemsVisitor(), 'warn')); ``` ================================================ FILE: packages/validators/package.json ================================================ { "name": "@codama/validators", "version": "1.6.0", "description": "Validator visitors for the Codama framework", "exports": { "types": "./dist/types/index.d.ts", "react-native": "./dist/index.react-native.mjs", "browser": { "import": "./dist/index.browser.mjs", "require": "./dist/index.browser.cjs" }, "node": { "import": "./dist/index.node.mjs", "require": "./dist/index.node.cjs" } }, "browser": { "./dist/index.node.cjs": "./dist/index.browser.cjs", "./dist/index.node.mjs": "./dist/index.browser.mjs" }, "main": "./dist/index.node.cjs", "module": "./dist/index.node.mjs", "react-native": "./dist/index.react-native.mjs", "types": "./dist/types/index.d.ts", "type": "commonjs", "files": [ "./dist/types", "./dist/index.*" ], "sideEffects": false, "keywords": [ "solana", "framework", "standard", "visitors" ], "scripts": { "build": "rimraf dist && tsup && tsc -p ./tsconfig.declarations.json", "dev": "vitest --project node", "lint": "eslint . && prettier --check .", "lint:fix": "eslint --fix . && prettier --write .", "test": "pnpm test:types && pnpm test:treeshakability && pnpm test:unit", "test:treeshakability": "for file in dist/index.*.mjs; do agadoo $file; done", "test:types": "tsc --noEmit", "test:unit": "vitest run" }, "dependencies": { "@codama/errors": "workspace:*", "@codama/nodes": "workspace:*", "@codama/visitors-core": "workspace:*" }, "license": "MIT", "repository": { "type": "git", "url": "https://github.com/codama-idl/codama" }, "bugs": { "url": "http://github.com/codama-idl/codama/issues" }, "browserslist": [ "supports bigint and not dead", "maintained node versions" ] } ================================================ FILE: packages/validators/src/ValidationItem.ts ================================================ import { Node } from '@codama/nodes'; import { NodePath, NodeStack } from '@codama/visitors-core'; export const LOG_LEVELS = ['debug', 'trace', 'info', 'warn', 'error'] as const; export type LogLevel = (typeof LOG_LEVELS)[number]; export type ValidationItem = { level: LogLevel; message: string; node: Node; path: NodePath; }; export function validationItem( level: LogLevel, message: string, node: Node, path: NodePath | NodeStack, ): ValidationItem { return { level, message, node, path: Array.isArray(path) ? path : (path as NodeStack).getPath(), }; } export const getLevelIndex = (level: LogLevel): number => LOG_LEVELS.indexOf(level); ================================================ FILE: packages/validators/src/getValidationItemsVisitor.ts ================================================ import { camelCase, getAllInstructionArguments, isNode } from '@codama/nodes'; import { extendVisitor, getResolvedInstructionInputsVisitor, LinkableDictionary, mergeVisitor, NodeStack, pipe, recordLinkablesOnFirstVisitVisitor, recordNodeStackVisitor, visit, Visitor, } from '@codama/visitors-core'; import { ValidationItem, validationItem } from './ValidationItem'; export function getValidationItemsVisitor(): Visitor { const linkables = new LinkableDictionary(); const stack = new NodeStack(); return pipe( mergeVisitor( () => [] as readonly ValidationItem[], (_, items) => items.flat(), ), v => recordLinkablesOnFirstVisitVisitor(v, linkables), v => recordNodeStackVisitor(v, stack), v => extendVisitor(v, { visitAccount(node, { next }) { const items = [] as ValidationItem[]; if (!node.name) { items.push(validationItem('error', 'Account has no name.', node, stack)); } return [...items, ...next(node)]; }, visitDefinedType(node, { next }) { const items = [] as ValidationItem[]; if (!node.name) { items.push(validationItem('error', 'Defined type has no name.', node, stack)); } return [...items, ...next(node)]; }, visitDefinedTypeLink(node, { next }) { const items = [] as ValidationItem[]; if (!node.name) { items.push(validationItem('error', 'Pointing to a defined type with no name.', node, stack)); } else if (!linkables.has(stack.getPath(node.kind))) { items.push( validationItem( 'error', `Pointing to a missing defined type named "${node.name}"`, node, stack, ), ); } return [...items, ...next(node)]; }, visitEnumEmptyVariantType(node, { next }) { const items = [] as ValidationItem[]; if (!node.name) { items.push(validationItem('error', 'Enum variant has no name.', node, stack)); } return [...items, ...next(node)]; }, visitEnumStructVariantType(node, { next }) { const items = [] as ValidationItem[]; if (!node.name) { items.push(validationItem('error', 'Enum variant has no name.', node, stack)); } return [...items, ...next(node)]; }, visitEnumTupleVariantType(node, { next }) { const items = [] as ValidationItem[]; if (!node.name) { items.push(validationItem('error', 'Enum variant has no name.', node, stack)); } return [...items, ...next(node)]; }, visitEnumType(node, { next }) { const items = [] as ValidationItem[]; if (node.variants.length === 0) { items.push(validationItem('warn', 'Enum has no variants.', node, stack)); } node.variants.forEach(variant => { if (!variant.name) { items.push(validationItem('error', 'Enum variant has no name.', node, stack)); } }); return [...items, ...next(node)]; }, visitError(node, { next }) { const items = [] as ValidationItem[]; if (!node.name) { items.push(validationItem('error', 'Error has no name.', node, stack)); } if (typeof node.code !== 'number') { items.push(validationItem('error', 'Error has no code.', node, stack)); } if (!node.message) { items.push(validationItem('warn', 'Error has no message.', node, stack)); } return [...items, ...next(node)]; }, visitInstruction(node, { next }) { const items = [] as ValidationItem[]; if (!node.name) { items.push(validationItem('error', 'Instruction has no name.', node, stack)); } // Check for duplicate account names. const accountNameHistogram = new Map(); node.accounts.forEach(account => { if (!account.name) { items.push(validationItem('error', 'Instruction account has no name.', node, stack)); return; } const count = (accountNameHistogram.get(account.name) ?? 0) + 1; accountNameHistogram.set(account.name, count); // Only throw an error once per duplicated names. if (count === 2) { items.push( validationItem( 'error', `Account name "${account.name}" is not unique in instruction "${node.name}".`, node, stack, ), ); } }); // Check for cyclic dependencies in account defaults. const cyclicCheckVisitor = getResolvedInstructionInputsVisitor(); try { visit(node, cyclicCheckVisitor); } catch (error) { items.push(validationItem('error', (error as Error).message, node, stack)); } // Check args. const names = getAllInstructionArguments(node).map(({ name }) => camelCase(name)); const duplicates = names.filter((e, i, a) => a.indexOf(e) !== i); const uniqueDuplicates = [...new Set(duplicates)]; const hasConflictingNames = uniqueDuplicates.length > 0; if (hasConflictingNames) { items.push( validationItem( 'error', `The names of the following instruction arguments are conflicting: ` + `[${uniqueDuplicates.join(', ')}].`, node, stack, ), ); } // Check arg defaults. getAllInstructionArguments(node).forEach(argument => { const { defaultValue } = argument; if (isNode(defaultValue, 'accountBumpValueNode')) { const defaultAccount = node.accounts.find(account => account.name === defaultValue.name); if (defaultAccount && defaultAccount.isSigner !== false) { items.push( validationItem( 'error', `Argument ${argument.name} cannot default to the bump attribute of ` + `the [${defaultValue.name}] account as it may be a Signer.`, node, stack, ), ); } } }); return [...items, ...next(node)]; }, visitProgram(node, { next }) { const items = [] as ValidationItem[]; if (!node.name) { items.push(validationItem('error', 'Program has no name.', node, stack)); } if (!node.publicKey) { items.push(validationItem('error', 'Program has no public key.', node, stack)); } if (!node.version) { items.push(validationItem('warn', 'Program has no version.', node, stack)); } if (!node.origin) { items.push(validationItem('info', 'Program has no origin.', node, stack)); } return [...items, ...next(node)]; }, visitStructFieldType(node, { next }) { const items = [] as ValidationItem[]; if (!node.name) { items.push(validationItem('error', 'Struct field has no name.', node, stack)); } return [...items, ...next(node)]; }, visitStructType(node, { next }) { const items = [] as ValidationItem[]; // Check for duplicate field names. const fieldNameHistogram = new Map(); node.fields.forEach(field => { if (!field.name) return; // Handled by TypeStructField const count = (fieldNameHistogram.get(field.name) ?? 0) + 1; fieldNameHistogram.set(field.name, count); // Only throw an error once per duplicated names. if (count === 2) { items.push( validationItem( 'error', `Struct field name "${field.name}" is not unique.`, field, stack, ), ); } }); return [...items, ...next(node)]; }, visitTupleType(node, { next }) { const items = [] as ValidationItem[]; if (node.items.length === 0) { items.push(validationItem('warn', 'Tuple has no items.', node, stack)); } return [...items, ...next(node)]; }, }), ); } ================================================ FILE: packages/validators/src/index.ts ================================================ export * from './getValidationItemsVisitor'; export * from './throwValidatorItemsVisitor'; export * from './ValidationItem'; ================================================ FILE: packages/validators/src/throwValidatorItemsVisitor.ts ================================================ import { CODAMA_ERROR__VISITORS__FAILED_TO_VALIDATE_NODE, CodamaError } from '@codama/errors'; import { NodeKind } from '@codama/nodes'; import { mapVisitor, Visitor } from '@codama/visitors-core'; import { getLevelIndex, LogLevel, ValidationItem } from './ValidationItem'; export function throwValidatorItemsVisitor( visitor: Visitor, throwLevel: LogLevel = 'error', ): Visitor { return mapVisitor(visitor, validationItems => { const levelHistogram = [...validationItems] .sort((a, b) => getLevelIndex(b.level) - getLevelIndex(a.level)) .reduce( (acc, item) => { acc[item.level] = (acc[item.level] ?? 0) + 1; return acc; }, {} as Record, ); const maxLevel = Object.keys(levelHistogram) .map(level => getLevelIndex(level as LogLevel)) .sort((a, b) => b - a)[0]; if (maxLevel >= getLevelIndex(throwLevel)) { const formattedHistogram = Object.keys(levelHistogram) .map(level => `${level}s: ${levelHistogram[level as LogLevel]}`) .join(', '); throw new CodamaError(CODAMA_ERROR__VISITORS__FAILED_TO_VALIDATE_NODE, { formattedHistogram, validationItems, }); } }); } ================================================ FILE: packages/validators/test/getValidationItemsVisitor.test.ts ================================================ import { programNode, publicKeyTypeNode, structFieldTypeNode, structTypeNode, tupleTypeNode } from '@codama/nodes'; import { visit } from '@codama/visitors-core'; import { expect, test } from 'vitest'; import { getValidationItemsVisitor, validationItem } from '../src'; test('it validates program nodes', () => { // Given the following program node with empty strings. const node = programNode({ accounts: [], definedTypes: [], errors: [], instructions: [], name: '', origin: undefined, publicKey: '', // @ts-expect-error Empty string does not match ProgramVersion. version: '', }); // When we get the validation items using a visitor. const items = visit(node, getValidationItemsVisitor()); // Then we expect the following validation errors. expect(items).toEqual([ validationItem('error', 'Program has no name.', node, []), validationItem('error', 'Program has no public key.', node, []), validationItem('warn', 'Program has no version.', node, []), validationItem('info', 'Program has no origin.', node, []), ]); }); test('it validates nested nodes', () => { // Given the following tuple with nested issues. const node = tupleTypeNode([ tupleTypeNode([]), structTypeNode([ structFieldTypeNode({ name: 'owner', type: publicKeyTypeNode() }), structFieldTypeNode({ name: 'owner', type: publicKeyTypeNode() }), ]), ]); // When we get the validation items using a visitor. const items = visit(node, getValidationItemsVisitor()); // Then we expect the following validation errors. const tupleNode = node.items[0]; const structNode = node.items[1]; expect(items).toEqual([ validationItem('warn', 'Tuple has no items.', tupleNode, [node]), validationItem('error', 'Struct field name "owner" is not unique.', structNode.fields[0], [node]), ]); }); ================================================ FILE: packages/validators/tsconfig.declarations.json ================================================ { "compilerOptions": { "declaration": true, "declarationMap": true, "emitDeclarationOnly": true, "outDir": "./dist/types" }, "extends": "./tsconfig.json", "include": ["src/index.ts", "src/types"] } ================================================ FILE: packages/validators/tsconfig.json ================================================ { "$schema": "https://json.schemastore.org/tsconfig", "compilerOptions": { "lib": [] }, "display": "@codama/validators", "extends": "../../tsconfig.json", "include": ["src", "test"] } ================================================ FILE: packages/validators/tsup.config.ts ================================================ import { defineConfig } from 'tsup'; import { getPackageBuildConfigs } from '../../tsup.config.base'; export default defineConfig(getPackageBuildConfigs()); ================================================ FILE: packages/validators/vitest.config.mts ================================================ import { defineConfig } from 'vitest/config'; import { getVitestConfig } from '../../vitest.config.base.mjs'; export default defineConfig({ test: { projects: [getVitestConfig('browser'), getVitestConfig('node'), getVitestConfig('react-native')], }, }); ================================================ FILE: packages/visitors/.gitignore ================================================ dist/ ================================================ FILE: packages/visitors/.prettierignore ================================================ dist/ test/e2e/ test-ledger/ target/ CHANGELOG.md ================================================ FILE: packages/visitors/LICENSE ================================================ MIT License Copyright (c) 2025 Codama Copyright (c) 2024 Metaplex Foundation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: packages/visitors/README.md ================================================ # Codama ➤ Visitors [![npm][npm-image]][npm-url] [![npm-downloads][npm-downloads-image]][npm-url] [npm-downloads-image]: https://img.shields.io/npm/dm/@codama/visitors.svg?style=flat [npm-image]: https://img.shields.io/npm/v/@codama/visitors.svg?style=flat&label=%40codama%2Fvisitors [npm-url]: https://www.npmjs.com/package/@codama/visitors This package offers various visitors for Codama IDLs to traverse and manipulate their nodes. ## Installation ```sh pnpm install @codama/visitors ``` > [!NOTE] > This package is included in the main [`codama`](../library) package. Meaning, you already have access to its content if you are installing Codama this way. > > ```sh > pnpm install codama > ``` ## Understanding visitors This package includes and re-exports the [`@codama/visitors-core`](../visitors-core/README.md) package which provides the core interfaces and functions to create and compose visitors. To get a better understanding of visitors and how they work, please refer to the [`@codama/visitors-core` documentation](../visitors-core/README.md). In the rest of this documentation, we focus on the high-level visitors that are only available in this package. The main goal of these visitors is to provide a set of specific operations that can be applied to Codama IDLs — as opposed to the generic primitives provided by the core package. For instance, this package offers visitors that unwrap link nodes, update instructions, add PDAs, set default values, and more. Let's go through all of them alphabetically. ## Available visitors ### `addPdasVisitor` This visitor adds `PdaNodes` to the desired `ProgramNodes`. It accepts an object where the keys are the program names and the values are the `PdaNodes` to add within these programs. ```ts codama.update( addPdasVisitor({ // Add a PDA to the 'token' program. token: [ { name: 'associatedToken', seeds: [ variablePdaSeedNode('mint', publicKeyTypeNode()), constantPdaSeedNode( publicKeyTypeNode(), publicKeyValueNode('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'), ), variablePdaSeedNode('owner', publicKeyTypeNode()), ], }, ], // Add two PDAs to the 'counter' program. counter: [ { name: 'counter', seeds: [variablePdaSeedNode('authority', publicKeyTypeNode())], }, { name: 'counterConfig', seeds: [variablePdaSeedNode('counter', publicKeyTypeNode())], }, ], }), ); ``` ### `createSubInstructionsFromEnumArgsVisitor` This visitor splits an instruction into multiple sub-instructions by using an enum argument such that each of its variants creates a different sub-instruction. It accepts an object where the keys are the instruction names and the values are the enum argument names that will be used to split the instruction. ```ts codama.update( createSubInstructionsFromEnumArgsVisitor({ mint: 'mintArgs', transfer: 'transferArgs', burn: 'burnArgs', }), ); ``` ### `deduplicateIdenticalDefinedTypesVisitor` This visitor goes through the `DefinedTypeNodes` of all `ProgramNodes` inside the Codama IDL and removes any duplicates. A `DefinedTypeNode` is considered a duplicate if it has the same name and data structure as another `DefinedTypeNode`. This is useful when you have multiple programs that share the same types. ```ts codama.update(deduplicateIdenticalDefinedTypesVisitor()); ``` ### `fillDefaultPdaSeedValuesVisitor` This visitor fills any missing `PdaSeedValueNodes` from `PdaValueNodes` using the provided `NodePath` such that: - If a `VariablePdaSeedNode` is of type `PublicKeyTypeNode` and the name of the seed matches the name of an account in the `InstructionNode`, then a new `PdaSeedValueNode` will be added with the matching account. - Otherwise, if a `VariablePdaSeedNode` is of any other type and the name of the seed matches the name of an argument in the `InstructionNode`, then a new `PdaSeedValueNode` will be added with the matching argument. - Otherwise, no `PdaSeedValueNode` will be added. It also requires a [`LinkableDictionary`](../visitors-core/README.md#linkable-dictionary) to resolve any link nodes and an optional `strictMode` boolean to throw an error if seeds are still missing after the visitor has run. Note that this visitor is mainly used for internal purposes. ```ts codama.update(fillDefaultPdaSeedValuesVisitor(instructionPath, linkables, strictMode)); ``` ### `flattenInstructionDataArgumentsVisitor` This visitor flattens any instruction arguments of type `StructTypeNode` such that their fields are no longer nested. This can be useful to simplify the data structure of an instruction. ```ts codama.update(flattenInstructionDataArgumentsVisitor()); ``` ### `flattenStructVisitor` This visitor flattens any struct fields that are also structs such that their fields are no longer nested. It accepts an object such that the keys are the struct names and the values are the field names to flatten or `"*"` to flatten all struct fields. ```ts codama.update( flattenStructVisitor({ counter: ['data', 'config'], escrow: '*', }), ); ``` ### `getDefinedTypeHistogramVisitor` This visitor goes through all `DefinedTypeNodes` and outputs a histogram of how many times each type is used in the Codama IDL. ```ts const histogram = codama.accept(getDefinedTypeHistogramVisitor()); ``` The returned histogram is an object such that the keys are the names of visited `DefinedTypeNodes` and the values are objects with properties described below. ```ts export type DefinedTypeHistogram = { [key: CamelCaseString | `${CamelCaseString}.${CamelCaseString}`]: { // The number of times the type is used as a direct instruction argument. directlyAsInstructionArgs: number; // The number of times the type is used in account data. inAccounts: number; // The number of times the type is used in other defined types. inDefinedTypes: number; // The number of times the type is used in event payloads. inEvents: number; // The number of times the type is used in instruction arguments. inInstructionArgs: number; // The number of times the type is used in total. total: number; }; }; ``` This histogram is used internally in other visitors to understand how types are used before applying transformations. ### `setAccountDiscriminatorFromFieldVisitor` This visitor helps set account discriminators based on a field in the account data and the value it should take. This is typically used on the very first field of the account data which usually refers to a discriminator value that helps distinguish between multiple accounts in a program. ```ts codama.update( setAccountDiscriminatorFromFieldVisitor({ counter: { field: 'discriminator', value: k.enumValueNode('accountState', 'counter') }, escrow: { field: 'discriminator', value: k.enumValueNode('accountState', 'escrow') }, vault: { field: 'discriminator', value: k.enumValueNode('accountState', 'vault') }, }), ); ``` ### `setFixedAccountSizesVisitor` This visitor uses the [`getByteSizeVisitor`](../visitors-core/README.md#getbytesizevisitor) to check the size of all `AccountNodes` and, if a fixed-size is identified, it sets the `size` property of the account to that value. ```ts codama.update(setFixedAccountSizesVisitor()); ``` ### `setInstructionAccountDefaultValuesVisitor` This visitor helps set the default values of instruction accounts in bulk. It accepts an array of "rule" objects that must contain the default value to set and the name of the instruction account to set it on. The account name may also be a regular expression to match more complex patterns. ```ts codama.update( setInstructionAccountDefaultValuesVisitor([ { // Set this public key as default value to any account named 'counterProgram'. account: 'counterProgram', defaultValue: publicKeyValueNode('MyCounterProgram11111111111111111111111111'), }, { // Set this PDA as default value to any account named 'associatedToken' or 'ata'. account: /^(associatedToken|ata)$/, defaultValue: pdaValueNode('associatedToken'), }, ]), ); ``` ### `setInstructionDiscriminatorsVisitor` This visitor adds a new instruction argument to each of the provided instruction names. The new argument is added before any existing argument and marked as a discriminator of the instruction. This is useful if your Codama IDL is missing discriminators in the instruction data. ```ts codama.update( setInstructionDiscriminatorsVisitor({ mint: { name: 'discriminator', type: numberTypeNode('u8'), value: numberValueNode(0) }, transfer: { name: 'discriminator', type: numberTypeNode('u8'), value: numberValueNode(1) }, burn: { name: 'discriminator', type: numberTypeNode('u8'), value: numberValueNode(2) }, }), ); ``` ### `setNumberWrappersVisitor` This visitor helps wrap `NumberTypeNodes` matching a given name with a specific number wrapper. ```ts codama.update( setNumberWrappersVisitor({ lamports: { kind: 'SolAmount' }, timestamp: { kind: 'DateTime' }, percent: { decimals: 2, kind: 'Amount', unit: '%' }, }), ); ``` ### `setStructDefaultValuesVisitor` This visitor sets default values for all provided fields of a struct. It accepts an object where the keys are the struct names and the values are objects that map field names to their new default values. ```ts codama.update( setStructDefaultValuesVisitor({ person: { age: numberValueNode(42), dateOfBirth: noneValueNode(), }, counter: { count: numberValueNode(0), }, }), ); ``` ### `transformDefinedTypesIntoAccountsVisitor` This visitor transforms `DefinedTypeNodes` matching the provided names into `AccountNodes` within the same `ProgramNode`. ```ts codama.update(transformDefinedTypesIntoAccountsVisitor(['counter', 'escrow'])); ``` ### `transformU8ArraysToBytesVisitor` This visitor transforms any fixed-size array of `u8` numbers into a fixed-size `BytesTypeNode`. ```ts codama.update(transformU8ArraysToBytesVisitor()); ``` ### `unwrapDefinedTypesVisitor` This visitor replaces any `DefinedTypeLinkNode` with the actual `DefinedTypeNode` it points to. By default, it unwraps all defined types, but you can provide an array of names to only unwrap specific types. Note that if multiple link nodes point to the same defined type, each link node will be replaced by a copy of the defined type. ```ts codama.update(unwrapDefinedTypesVisitor(['counter', 'escrow'])); ``` ### `unwrapInstructionArgsDefinedTypesVisitor` This visitor replaces `DefinedTypeLinkNodes` used only once inside an instruction argument with the actual `DefinedTypeNodes` they refer to. ```ts codama.update(unwrapInstructionArgsDefinedTypesVisitor()); ``` ### `unwrapTupleEnumWithSingleStructVisitor` This visitor transforms `EnumTupleVariantTypeNodes` with a single `StructTypeNode` item into `EnumStructVariantTypeNodes`. By default, it will unwrap all tuple variants matching that criteria, but you can provide an array of names to only unwrap specific variants. ```ts codama.update(unwrapTupleEnumWithSingleStructVisitor()); ``` ### `unwrapTypeDefinedLinksVisitor` This visitor replaces any `DefinedTypeLinkNode` matching the provided `NodeSelectors` with the actual `DefinedTypeNode` it points to. Contrary to the `unwrapDefinedTypesVisitor` though, it only replaces the requested `DefinedTypeLinkNodes` and does not remove the associated `DefinedTypeNode` from its `ProgramNode`. ```ts codama.update(unwrapTypeDefinedLinksVisitor(['[accountNode]counter.data', '[instructionNode]transfer.config'])); ``` ### `updateAccountsVisitor` This visitor allows us to update various aspects of `AccountNodes` and/or delete them. It accepts an object where the keys are the account names and the values are the operations to apply to these accounts. ```ts codama.update( updateAccountsVisitor({ vault: { // Rename the 'vault' account to 'safe'. name: 'safe', // Rename the 'owner' field to 'authority'. data: { owner: 'authority' }, // Create a new PDA node and link it to this account. seeds: [variablePdaSeedNode('authority', publicKeyTypeNode())], }, counter: { // Delete the 'counter' account. delete: true, }, }), ); ``` ### `updateDefinedTypesVisitor` This visitor allows us to update various aspects of `DefinedTypeNode` and/or delete them. It accepts an object where the keys are the defined type names and the values are the operations to apply to these types. ```ts codama.update( updateDefinedTypesVisitor({ options: { // Rename the 'options' type to 'configs'. name: 'configs', // Rename the 'sol' field to 'lamports'. data: { sol: 'lamports' }, }, player: { // Delete the 'player' type. delete: true, }, }), ); ``` ### `updateErrorsVisitor` This visitor allows us to update various aspects of `ErrorNodes` and/or delete them. It accepts an object where the keys are the error names and the values are the operations to apply to these errors. ```ts codama.update( updateErrorsVisitor({ invalidPda: { // Rename the 'invalidPda' error to 'invalidProgramDerivedAddress'. name: 'invalidProgramDerivedAddress', // Change the error message. message: 'The program-derived address is invalid.', // Change the error code. code: 123, }, accountMismatch: { // Delete the 'accountMismatch' error. delete: true, }, }), ); ``` ### `updateInstructionsVisitor` This visitor allows us to update various aspects of `InstructionNodes` and/or delete them. It accepts an object where the keys are the instruction names and the values are the operations to apply to these instructions. ```ts codama.update( updateInstructionsVisitor({ send: { // Rename the 'send' instruction to 'transfer'. name: 'transfer', accounts: { // Rename the 'owner' instruction account to 'authority'. owner: { name: 'authority' }, // Set a default value for the 'associatedToken' instruction account. associatedToken: { defaultValue: pdaValueNode('associatedToken') }, // Update the signer status of the 'payer' instruction account to `true`. payer: { isSigner: true }, // Mark the 'mint' instruction account as optional. mint: { isOptional: true }, }, arguments: { // Set a default value for the 'amount' instruction argument to 1. amount: { defaultValue: numberValueNode(1) }, // Rename the 'decimals' instruction argument to 'mintDecimals'. decimals: { name: 'mintDecimals' }, }, }, burn: { // Delete the 'burn' instruction. delete: true, }, }), ); ``` ### `updateProgramsVisitor` This visitor allows us to update various aspects of `ProgramNodes` and/or delete them. It accepts an object where the keys are the program names and the values are the operations to apply to these programs. ```ts codama.update( updateProgramsVisitor({ splToken: { // Rename the 'splToken' program to 'token'. name: 'token', // Change the program version. version: '3.0.0', // Change the program's public key. publicKey: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', }, splAssociatedToken: { // Delete the 'splAssociatedToken' program. delete: true, }, }), ); ``` ================================================ FILE: packages/visitors/package.json ================================================ { "name": "@codama/visitors", "version": "1.6.0", "description": "All visitors for the Codama framework", "exports": { "types": "./dist/types/index.d.ts", "react-native": "./dist/index.react-native.mjs", "browser": { "import": "./dist/index.browser.mjs", "require": "./dist/index.browser.cjs" }, "node": { "import": "./dist/index.node.mjs", "require": "./dist/index.node.cjs" } }, "browser": { "./dist/index.node.cjs": "./dist/index.browser.cjs", "./dist/index.node.mjs": "./dist/index.browser.mjs" }, "main": "./dist/index.node.cjs", "module": "./dist/index.node.mjs", "react-native": "./dist/index.react-native.mjs", "types": "./dist/types/index.d.ts", "type": "commonjs", "files": [ "./dist/types", "./dist/index.*" ], "sideEffects": false, "keywords": [ "solana", "framework", "standard", "visitors" ], "scripts": { "build": "rimraf dist && tsup && tsc -p ./tsconfig.declarations.json", "dev": "vitest --project node", "lint": "eslint . && prettier --check .", "lint:fix": "eslint --fix . && prettier --write .", "test": "pnpm test:types && pnpm test:treeshakability && pnpm test:unit", "test:treeshakability": "for file in dist/index.*.mjs; do agadoo $file; done", "test:types": "tsc --noEmit", "test:unit": "vitest run" }, "dependencies": { "@codama/errors": "workspace:*", "@codama/nodes": "workspace:*", "@codama/visitors-core": "workspace:*" }, "license": "MIT", "repository": { "type": "git", "url": "https://github.com/codama-idl/codama" }, "bugs": { "url": "http://github.com/codama-idl/codama/issues" }, "browserslist": [ "supports bigint and not dead", "maintained node versions" ] } ================================================ FILE: packages/visitors/src/addPdasVisitor.ts ================================================ import { CODAMA_ERROR__VISITORS__CANNOT_ADD_DUPLICATED_PDA_NAMES, CodamaError } from '@codama/errors'; import { assertIsNode, camelCase, pdaNode, PdaNodeInput, programNode } from '@codama/nodes'; import { bottomUpTransformerVisitor } from '@codama/visitors-core'; export function addPdasVisitor(pdas: Record[]>) { return bottomUpTransformerVisitor( Object.entries(pdas).map(([uncasedProgramName, newPdas]) => { const programName = camelCase(uncasedProgramName); return { select: `[programNode]${programName}`, transform: node => { assertIsNode(node, 'programNode'); const existingPdaNames = new Set(node.pdas.map(pda => pda.name)); const newPdaNames = new Set(newPdas.map(pda => pda.name)); const overlappingPdaNames = new Set([...existingPdaNames].filter(name => newPdaNames.has(name))); if (overlappingPdaNames.size > 0) { throw new CodamaError(CODAMA_ERROR__VISITORS__CANNOT_ADD_DUPLICATED_PDA_NAMES, { duplicatedPdaNames: [...overlappingPdaNames], program: node, programName: node.name, }); } return programNode({ ...node, pdas: [...node.pdas, ...newPdas.map(({ name, seeds, docs }) => pdaNode({ docs, name, seeds }))], }); }, }; }), ); } ================================================ FILE: packages/visitors/src/createSubInstructionsFromEnumArgsVisitor.ts ================================================ import { CODAMA_ERROR__VISITORS__INSTRUCTION_ENUM_ARGUMENT_NOT_FOUND, CodamaError } from '@codama/errors'; import { assertIsNode, camelCase, EnumTypeNode, instructionArgumentNode, InstructionNode, instructionNode, isNode, numberTypeNode, numberValueNode, } from '@codama/nodes'; import { BottomUpNodeTransformerWithSelector, bottomUpTransformerVisitor, LinkableDictionary, pipe, recordLinkablesOnFirstVisitVisitor, } from '@codama/visitors-core'; import { flattenInstructionArguments } from './flattenInstructionDataArgumentsVisitor'; export function createSubInstructionsFromEnumArgsVisitor(map: Record) { const linkables = new LinkableDictionary(); const visitor = bottomUpTransformerVisitor( Object.entries(map).map( ([selector, argNameInput]): BottomUpNodeTransformerWithSelector => ({ select: ['[instructionNode]', selector], transform: (node, stack) => { assertIsNode(node, 'instructionNode'); const argFields = node.arguments; const argName = camelCase(argNameInput); const argFieldIndex = argFields.findIndex(field => field.name === argName); const argField = argFieldIndex >= 0 ? argFields[argFieldIndex] : null; if (!argField) { throw new CodamaError(CODAMA_ERROR__VISITORS__INSTRUCTION_ENUM_ARGUMENT_NOT_FOUND, { argumentName: argName, instruction: node, instructionName: node.name, }); } let argType: EnumTypeNode; if (isNode(argField.type, 'enumTypeNode')) { argType = argField.type; } else if ( isNode(argField.type, 'definedTypeLinkNode') && linkables.has([...stack.getPath(), argField.type]) ) { const linkedType = linkables.get([...stack.getPath(), argField.type])?.type; assertIsNode(linkedType, 'enumTypeNode'); argType = linkedType; } else { throw new CodamaError(CODAMA_ERROR__VISITORS__INSTRUCTION_ENUM_ARGUMENT_NOT_FOUND, { argumentName: argName, instruction: node, instructionName: node.name, }); } const subInstructions = argType.variants.map((variant, index): InstructionNode => { const subName = camelCase(`${node.name} ${variant.name}`); const subFields = argFields.slice(0, argFieldIndex); subFields.push( instructionArgumentNode({ defaultValue: numberValueNode(index), defaultValueStrategy: 'omitted', name: `${subName}Discriminator`, type: numberTypeNode('u8'), }), ); if (isNode(variant, 'enumStructVariantTypeNode')) { subFields.push( instructionArgumentNode({ ...argField, type: variant.struct, }), ); } else if (isNode(variant, 'enumTupleVariantTypeNode')) { subFields.push( instructionArgumentNode({ ...argField, type: variant.tuple, }), ); } subFields.push(...argFields.slice(argFieldIndex + 1)); return instructionNode({ ...node, arguments: flattenInstructionArguments(subFields), name: subName, }); }); return instructionNode({ ...node, subInstructions: [...(node.subInstructions ?? []), ...subInstructions], }); }, }), ), ); return pipe(visitor, v => recordLinkablesOnFirstVisitVisitor(v, linkables)); } ================================================ FILE: packages/visitors/src/deduplicateIdenticalDefinedTypesVisitor.ts ================================================ import { assertIsNode, DefinedTypeNode, getAllPrograms, ProgramNode } from '@codama/nodes'; import { deleteNodesVisitor, getUniqueHashStringVisitor, NodeSelector, rootNodeVisitor, visit, } from '@codama/visitors-core'; type DefinedTypeWithProgram = { program: ProgramNode; type: DefinedTypeNode; }; export function deduplicateIdenticalDefinedTypesVisitor() { return rootNodeVisitor(root => { const typeMap = new Map(); // Fill the type map with all defined types. const allPrograms = getAllPrograms(root); allPrograms.forEach(program => { program.definedTypes.forEach(type => { const typeWithProgram = { program, type }; const list = typeMap.get(type.name) ?? []; typeMap.set(type.name, [...list, typeWithProgram]); }); }); // Remove all types that are not duplicated. typeMap.forEach((list, name) => { if (list.length <= 1) { typeMap.delete(name); } }); // Remove duplicates whose types are not equal. const hashVisitor = getUniqueHashStringVisitor({ removeDocs: true }); typeMap.forEach((list, name) => { const types = list.map(item => visit(item.type, hashVisitor)); const typesAreEqual = types.every((type, _, arr) => type === arr[0]); if (!typesAreEqual) { typeMap.delete(name); } }); // Get the selectors for all defined types that needs deleting. // Thus, we must select all but the first duplicate of each list. const deleteSelectors = Array.from(typeMap.values()) // Order lists by program index, get their tails and flatten. .flatMap(list => { const sortedList = list.sort((a, b) => allPrograms.indexOf(a.program) - allPrograms.indexOf(b.program)); const [, ...sortedListTail] = sortedList; return sortedListTail; }) // Get selectors from the defined types and their programs. .map(({ program, type }): NodeSelector => `[programNode]${program.name}.[definedTypeNode]${type.name}`); // Delete the identified nodes if any. if (deleteSelectors.length > 0) { const newRoot = visit(root, deleteNodesVisitor(deleteSelectors)); assertIsNode(newRoot, 'rootNode'); return newRoot; } return root; }); } ================================================ FILE: packages/visitors/src/fillDefaultPdaSeedValuesVisitor.ts ================================================ import { CODAMA_ERROR__VISITORS__INVALID_PDA_SEED_VALUES, CodamaError } from '@codama/errors'; import { accountValueNode, argumentValueNode, assertIsNode, getAllInstructionArguments, INSTRUCTION_INPUT_VALUE_NODES, InstructionInputValueNode, InstructionNode, isNode, isNodeFilter, PdaNode, PdaSeedValueNode, pdaSeedValueNode, pdaValueNode, } from '@codama/nodes'; import { extendVisitor, getLastNodeFromPath, identityVisitor, LinkableDictionary, NodePath, pipe, Visitor, } from '@codama/visitors-core'; /** * Fills in default values for variable PDA seeds that are not explicitly provided. * Namely, public key seeds are filled with an accountValueNode using the seed name * and other types of seeds are filled with an argumentValueNode using the seed name. * * An instruction and linkable dictionary are required to determine which seeds are * valids and to find the pdaLinkNode for the seed respectively. Any invalid default * seed won't be filled in. * * Strict mode goes one step further and will throw an error if the final array of * pdaSeedValueNodes contains invalid seeds or if there aren't enough variable seeds. */ export function fillDefaultPdaSeedValuesVisitor( instructionPath: NodePath, linkables: LinkableDictionary, strictMode: boolean = false, ) { const instruction = getLastNodeFromPath(instructionPath); return pipe(identityVisitor({ keys: INSTRUCTION_INPUT_VALUE_NODES }), v => extendVisitor(v, { visitPdaValue(node, { next }) { const visitedNode = next(node); assertIsNode(visitedNode, 'pdaValueNode'); const foundPda = isNode(visitedNode.pda, 'pdaNode') ? visitedNode.pda : linkables.get([...instructionPath, visitedNode.pda]); if (!foundPda) return visitedNode; const seeds = addDefaultSeedValuesFromPdaWhenMissing(instruction, foundPda, visitedNode.seeds); if (strictMode && !allSeedsAreValid(instruction, foundPda, seeds)) { throw new CodamaError(CODAMA_ERROR__VISITORS__INVALID_PDA_SEED_VALUES, { instruction, instructionName: instruction.name, pda: foundPda, pdaName: foundPda.name, }); } return pdaValueNode(visitedNode.pda, seeds); }, }), ) as Visitor; } function addDefaultSeedValuesFromPdaWhenMissing( instruction: InstructionNode, pda: PdaNode, existingSeeds: PdaSeedValueNode[], ): PdaSeedValueNode[] { const existingSeedNames = new Set(existingSeeds.map(seed => seed.name)); const defaultSeeds = getDefaultSeedValuesFromPda(instruction, pda).filter( seed => !existingSeedNames.has(seed.name), ); return [...existingSeeds, ...defaultSeeds]; } function getDefaultSeedValuesFromPda(instruction: InstructionNode, pda: PdaNode): PdaSeedValueNode[] { return pda.seeds.flatMap((seed): PdaSeedValueNode[] => { if (!isNode(seed, 'variablePdaSeedNode')) return []; const hasMatchingAccount = instruction.accounts.some(a => a.name === seed.name); if (isNode(seed.type, 'publicKeyTypeNode') && hasMatchingAccount) { return [pdaSeedValueNode(seed.name, accountValueNode(seed.name))]; } const hasMatchingArgument = getAllInstructionArguments(instruction).some(a => a.name === seed.name); if (hasMatchingArgument) { return [pdaSeedValueNode(seed.name, argumentValueNode(seed.name))]; } return []; }); } function allSeedsAreValid(instruction: InstructionNode, foundPda: PdaNode, seeds: PdaSeedValueNode[]) { const hasAllVariableSeeds = foundPda.seeds.filter(isNodeFilter('variablePdaSeedNode')).length === seeds.length; const allAccountsName = instruction.accounts.map(a => a.name); const allArgumentsName = getAllInstructionArguments(instruction).map(a => a.name); const validSeeds = seeds.every(seed => { if (isNode(seed.value, 'accountValueNode')) { return allAccountsName.includes(seed.value.name); } if (isNode(seed.value, 'argumentValueNode')) { return allArgumentsName.includes(seed.value.name); } return true; }); return hasAllVariableSeeds && validSeeds; } ================================================ FILE: packages/visitors/src/flattenInstructionDataArgumentsVisitor.ts ================================================ import { CODAMA_ERROR__VISITORS__CANNOT_FLATTEN_STRUCT_WITH_CONFLICTING_ATTRIBUTES, CodamaError } from '@codama/errors'; import { assertIsNode, camelCase, InstructionArgumentNode, instructionArgumentNode, instructionNode, isNode, } from '@codama/nodes'; import { bottomUpTransformerVisitor } from '@codama/visitors-core'; export function flattenInstructionDataArgumentsVisitor() { return bottomUpTransformerVisitor([ { select: '[instructionNode]', transform: instruction => { assertIsNode(instruction, 'instructionNode'); return instructionNode({ ...instruction, arguments: flattenInstructionArguments(instruction.arguments), }); }, }, ]); } export type FlattenInstructionArgumentsConfig = string[] | '*'; export const flattenInstructionArguments = ( nodes: InstructionArgumentNode[], options: FlattenInstructionArgumentsConfig = '*', ): InstructionArgumentNode[] => { const camelCaseOptions = options === '*' ? options : options.map(camelCase); const shouldInline = (node: InstructionArgumentNode): boolean => options === '*' || camelCaseOptions.includes(camelCase(node.name)); const inlinedArguments = nodes.flatMap(node => { if (isNode(node.type, 'structTypeNode') && shouldInline(node)) { return node.type.fields.map(field => instructionArgumentNode({ ...field })); } return node; }); const inlinedFieldsNames = inlinedArguments.map(arg => arg.name); const duplicates = inlinedFieldsNames.filter((e, i, a) => a.indexOf(e) !== i); const uniqueDuplicates = [...new Set(duplicates)]; const hasConflictingNames = uniqueDuplicates.length > 0; if (hasConflictingNames) { throw new CodamaError(CODAMA_ERROR__VISITORS__CANNOT_FLATTEN_STRUCT_WITH_CONFLICTING_ATTRIBUTES, { conflictingAttributes: uniqueDuplicates, }); } return hasConflictingNames ? nodes : inlinedArguments; }; ================================================ FILE: packages/visitors/src/flattenStructVisitor.ts ================================================ import { CODAMA_ERROR__VISITORS__CANNOT_FLATTEN_STRUCT_WITH_CONFLICTING_ATTRIBUTES, CodamaError } from '@codama/errors'; import { assertIsNode, camelCase, isNode, Node, StructFieldTypeNode, StructTypeNode, structTypeNode, } from '@codama/nodes'; import { BottomUpNodeTransformerWithSelector, bottomUpTransformerVisitor } from '@codama/visitors-core'; export type FlattenStructOptions = string[] | '*'; export function flattenStructVisitor(map: Record) { return bottomUpTransformerVisitor( Object.entries(map).map( ([stack, options]): BottomUpNodeTransformerWithSelector => ({ select: `${stack}.[structTypeNode]`, transform: node => flattenStruct(node, options), }), ), ); } export const flattenStruct = (node: Node, options: FlattenStructOptions = '*'): StructTypeNode => { assertIsNode(node, 'structTypeNode'); const camelCaseOptions = options === '*' ? options : options.map(camelCase); const shouldInline = (field: StructFieldTypeNode): boolean => options === '*' || camelCaseOptions.includes(camelCase(field.name)); const inlinedFields = node.fields.flatMap(field => { if (isNode(field.type, 'structTypeNode') && shouldInline(field)) { return field.type.fields; } return [field]; }); const inlinedFieldsNames = inlinedFields.map(arg => arg.name); const duplicates = inlinedFieldsNames.filter((e, i, a) => a.indexOf(e) !== i); const uniqueDuplicates = [...new Set(duplicates)]; const hasConflictingNames = uniqueDuplicates.length > 0; if (hasConflictingNames) { throw new CodamaError(CODAMA_ERROR__VISITORS__CANNOT_FLATTEN_STRUCT_WITH_CONFLICTING_ATTRIBUTES, { conflictingAttributes: uniqueDuplicates, }); } return hasConflictingNames ? node : structTypeNode(inlinedFields); }; ================================================ FILE: packages/visitors/src/getDefinedTypeHistogramVisitor.ts ================================================ import { CamelCaseString } from '@codama/nodes'; import { extendVisitor, findProgramNodeFromPath, interceptVisitor, mergeVisitor, NodeStack, pipe, recordNodeStackVisitor, visit, Visitor, } from '@codama/visitors-core'; type DefinedTypeHistogramKey = CamelCaseString | `${CamelCaseString}.${CamelCaseString}`; export type DefinedTypeHistogram = { [key: DefinedTypeHistogramKey]: { directlyAsInstructionArgs: number; inAccounts: number; inDefinedTypes: number; inEvents: number; inInstructionArgs: number; total: number; }; }; function mergeHistograms(histograms: DefinedTypeHistogram[]): DefinedTypeHistogram { const result: DefinedTypeHistogram = {}; histograms.forEach(histogram => { Object.keys(histogram).forEach(key => { const mainCaseKey = key as CamelCaseString; if (result[mainCaseKey] === undefined) { result[mainCaseKey] = histogram[mainCaseKey]; } else { result[mainCaseKey].total += histogram[mainCaseKey].total; result[mainCaseKey].inAccounts += histogram[mainCaseKey].inAccounts; result[mainCaseKey].inDefinedTypes += histogram[mainCaseKey].inDefinedTypes; result[mainCaseKey].inEvents += histogram[mainCaseKey].inEvents; result[mainCaseKey].inInstructionArgs += histogram[mainCaseKey].inInstructionArgs; result[mainCaseKey].directlyAsInstructionArgs += histogram[mainCaseKey].directlyAsInstructionArgs; } }); }); return result; } export function getDefinedTypeHistogramVisitor(): Visitor { const stack = new NodeStack(); let mode: 'account' | 'definedType' | 'event' | 'instruction' | null = null; let stackLevel = 0; return pipe( mergeVisitor( () => ({}) as DefinedTypeHistogram, (_, histograms) => mergeHistograms(histograms), ), v => interceptVisitor(v, (node, next) => { stackLevel += 1; const newNode = next(node); stackLevel -= 1; return newNode; }), v => extendVisitor(v, { visitAccount(node, { self }) { mode = 'account'; stackLevel = 0; const histogram = visit(node.data, self); mode = null; return histogram; }, visitDefinedType(node, { self }) { mode = 'definedType'; stackLevel = 0; const histogram = visit(node.type, self); mode = null; return histogram; }, visitDefinedTypeLink(node) { const program = findProgramNodeFromPath(stack.getPath()); const key = program ? `${program.name}.${node.name}` : node.name; return { [key]: { directlyAsInstructionArgs: Number(mode === 'instruction' && stackLevel <= 1), inAccounts: Number(mode === 'account'), inDefinedTypes: Number(mode === 'definedType'), inEvents: Number(mode === 'event'), inInstructionArgs: Number(mode === 'instruction'), total: 1, }, }; }, visitEvent(node, { self }) { mode = 'event'; stackLevel = 0; const histogram = visit(node.data, self); mode = null; return histogram; }, visitInstruction(node, { self }) { mode = 'instruction'; stackLevel = 0; const dataHistograms = node.arguments.map(arg => visit(arg, self)); const extraHistograms = (node.extraArguments ?? []).map(arg => visit(arg, self)); mode = null; const subHistograms = (node.subInstructions ?? []).map(ix => visit(ix, self)); return mergeHistograms([...dataHistograms, ...extraHistograms, ...subHistograms]); }, }), v => recordNodeStackVisitor(v, stack), ); } ================================================ FILE: packages/visitors/src/index.ts ================================================ export * from '@codama/visitors-core'; export * from './addPdasVisitor'; export * from './createSubInstructionsFromEnumArgsVisitor'; export * from './deduplicateIdenticalDefinedTypesVisitor'; export * from './fillDefaultPdaSeedValuesVisitor'; export * from './flattenInstructionDataArgumentsVisitor'; export * from './flattenStructVisitor'; export * from './getDefinedTypeHistogramVisitor'; export * from './setAccountDiscriminatorFromFieldVisitor'; export * from './setFixedAccountSizesVisitor'; export * from './setInstructionAccountDefaultValuesVisitor'; export * from './setInstructionDiscriminatorsVisitor'; export * from './setNumberWrappersVisitor'; export * from './setStructDefaultValuesVisitor'; export * from './transformDefinedTypesIntoAccountsVisitor'; export * from './transformU8ArraysToBytesVisitor'; export * from './unwrapDefinedTypesVisitor'; export * from './unwrapInstructionArgsDefinedTypesVisitor'; export * from './unwrapTupleEnumWithSingleStructVisitor'; export * from './unwrapTypeDefinedLinksVisitor'; export * from './updateAccountsVisitor'; export * from './updateDefinedTypesVisitor'; export * from './updateErrorsVisitor'; export * from './updateInstructionsVisitor'; export * from './updateProgramsVisitor'; ================================================ FILE: packages/visitors/src/renameHelpers.ts ================================================ import { enumEmptyVariantTypeNode, enumStructVariantTypeNode, enumTupleVariantTypeNode, EnumTypeNode, enumTypeNode, EnumVariantTypeNode, isNode, structFieldTypeNode, StructTypeNode, structTypeNode, } from '@codama/nodes'; export function renameStructNode(node: StructTypeNode, map: Record): StructTypeNode { return structTypeNode( node.fields.map(field => (map[field.name] ? structFieldTypeNode({ ...field, name: map[field.name] }) : field)), ); } export function renameEnumNode(node: EnumTypeNode, map: Record): EnumTypeNode { return enumTypeNode( node.variants.map(variant => (map[variant.name] ? renameEnumVariant(variant, map[variant.name]) : variant)), { ...node }, ); } function renameEnumVariant(variant: EnumVariantTypeNode, newName: string) { if (isNode(variant, 'enumStructVariantTypeNode')) { return enumStructVariantTypeNode(newName, variant.struct); } if (isNode(variant, 'enumTupleVariantTypeNode')) { return enumTupleVariantTypeNode(newName, variant.tuple); } return enumEmptyVariantTypeNode(newName); } ================================================ FILE: packages/visitors/src/setAccountDiscriminatorFromFieldVisitor.ts ================================================ import { CODAMA_ERROR__VISITORS__ACCOUNT_FIELD_NOT_FOUND, CodamaError } from '@codama/errors'; import { accountNode, assertIsNode, fieldDiscriminatorNode, resolveNestedTypeNode, structFieldTypeNode, structTypeNode, transformNestedTypeNode, ValueNode, } from '@codama/nodes'; import { BottomUpNodeTransformerWithSelector, bottomUpTransformerVisitor } from '@codama/visitors-core'; export function setAccountDiscriminatorFromFieldVisitor( map: Record, ) { return bottomUpTransformerVisitor( Object.entries(map).map( ([selector, { field, value, offset }]): BottomUpNodeTransformerWithSelector => ({ select: ['[accountNode]', selector], transform: node => { assertIsNode(node, 'accountNode'); const accountData = resolveNestedTypeNode(node.data); const fieldIndex = accountData.fields.findIndex(f => f.name === field); if (fieldIndex < 0) { throw new CodamaError(CODAMA_ERROR__VISITORS__ACCOUNT_FIELD_NOT_FOUND, { account: node, missingField: field, name: node.name, }); } const fieldNode = accountData.fields[fieldIndex]; return accountNode({ ...node, data: transformNestedTypeNode(node.data, () => structTypeNode([ ...accountData.fields.slice(0, fieldIndex), structFieldTypeNode({ ...fieldNode, defaultValue: value, defaultValueStrategy: 'omitted', }), ...accountData.fields.slice(fieldIndex + 1), ]), ), discriminators: [fieldDiscriminatorNode(field, offset), ...(node.discriminators ?? [])], }); }, }), ), ); } ================================================ FILE: packages/visitors/src/setFixedAccountSizesVisitor.ts ================================================ import { accountNode, assertIsNode } from '@codama/nodes'; import { getByteSizeVisitor, getLastNodeFromPath, isNodePath, LinkableDictionary, pipe, recordLinkablesOnFirstVisitVisitor, topDownTransformerVisitor, visit, } from '@codama/visitors-core'; export function setFixedAccountSizesVisitor() { const linkables = new LinkableDictionary(); const visitor = topDownTransformerVisitor( [ { select: path => isNodePath(path, 'accountNode') && getLastNodeFromPath(path).size === undefined, transform: (node, stack) => { assertIsNode(node, 'accountNode'); const size = visit(node.data, getByteSizeVisitor(linkables, { stack })); if (size === null) return node; return accountNode({ ...node, size }) as typeof node; }, }, ], { keys: ['rootNode', 'programNode', 'accountNode'] }, ); return pipe(visitor, v => recordLinkablesOnFirstVisitVisitor(v, linkables)); } ================================================ FILE: packages/visitors/src/setInstructionAccountDefaultValuesVisitor.ts ================================================ import { camelCase, identityValueNode, InstructionAccountNode, InstructionInputValueNode, InstructionNode, instructionNode, payerValueNode, programIdValueNode, publicKeyValueNode, } from '@codama/nodes'; import { extendVisitor, LinkableDictionary, NodeStack, nonNullableIdentityVisitor, pipe, recordLinkablesOnFirstVisitVisitor, recordNodeStackVisitor, visit, } from '@codama/visitors-core'; import { fillDefaultPdaSeedValuesVisitor } from './fillDefaultPdaSeedValuesVisitor'; export type InstructionAccountDefaultRule = { /** The name of the instruction account or a pattern to match on it. */ account: RegExp | string; /** The default value to assign to it. */ defaultValue: InstructionInputValueNode; /** @defaultValue `false`. */ ignoreIfOptional?: boolean; /** @defaultValue Defaults to searching accounts on all instructions. */ instruction?: string; }; export const getCommonInstructionAccountDefaultRules = (): InstructionAccountDefaultRule[] => [ { account: /^(payer|feePayer)$/, defaultValue: payerValueNode(), ignoreIfOptional: true, }, { account: /^(authority)$/, defaultValue: identityValueNode(), ignoreIfOptional: true, }, { account: /^(programId)$/, defaultValue: programIdValueNode(), ignoreIfOptional: true, }, { account: /^(systemProgram|splSystemProgram)$/, defaultValue: publicKeyValueNode('11111111111111111111111111111111', 'splSystem'), ignoreIfOptional: true, }, { account: /^(tokenProgram|splTokenProgram)$/, defaultValue: publicKeyValueNode('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', 'splToken'), ignoreIfOptional: true, }, { account: /^(ataProgram|splAtaProgram)$/, defaultValue: publicKeyValueNode('ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL', 'splAssociatedToken'), ignoreIfOptional: true, }, { account: /^(tokenMetadataProgram|mplTokenMetadataProgram)$/, defaultValue: publicKeyValueNode('metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s', 'mplTokenMetadata'), ignoreIfOptional: true, }, { account: /^(tokenAuth|mplTokenAuth|authorization|mplAuthorization|auth|mplAuth)RulesProgram$/, defaultValue: publicKeyValueNode('auth9SigNpDKz4sJJ1DfCTuZrZNSAgh9sFD3rboVmgg', 'mplTokenAuthRules'), ignoreIfOptional: true, }, { account: /^(candyMachineProgram|mplCandyMachineProgram)$/, defaultValue: publicKeyValueNode('CndyV3LdqHUfDLmE5naZjVN8rBZz4tqhdefbAnjHG3JR', 'mplCandyMachine'), ignoreIfOptional: true, }, { account: /^(candyGuardProgram|mplCandyGuardProgram)$/, defaultValue: publicKeyValueNode('Guard1JwRhJkVH6XZhzoYxeBVQe872VH6QggF4BWmS9g', 'mplCandyGuard'), ignoreIfOptional: true, }, { account: /^(clockSysvar|sysvarClock)$/, defaultValue: publicKeyValueNode('SysvarC1ock11111111111111111111111111111111'), ignoreIfOptional: true, }, { account: /^(epochScheduleSysvar|sysvarEpochSchedule)$/, defaultValue: publicKeyValueNode('SysvarEpochSchedu1e111111111111111111111111'), ignoreIfOptional: true, }, { account: /^(instructions?Sysvar|sysvarInstructions?)(Account)?$/, defaultValue: publicKeyValueNode('Sysvar1nstructions1111111111111111111111111'), ignoreIfOptional: true, }, { account: /^(recentBlockhashesSysvar|sysvarRecentBlockhashes)$/, defaultValue: publicKeyValueNode('SysvarRecentB1ockHashes11111111111111111111'), ignoreIfOptional: true, }, { account: /^(rent|rentSysvar|sysvarRent)$/, defaultValue: publicKeyValueNode('SysvarRent111111111111111111111111111111111'), ignoreIfOptional: true, }, { account: /^(rewardsSysvar|sysvarRewards)$/, defaultValue: publicKeyValueNode('SysvarRewards111111111111111111111111111111'), ignoreIfOptional: true, }, { account: /^(slotHashesSysvar|sysvarSlotHashes)$/, defaultValue: publicKeyValueNode('SysvarS1otHashes111111111111111111111111111'), ignoreIfOptional: true, }, { account: /^(slotHistorySysvar|sysvarSlotHistory)$/, defaultValue: publicKeyValueNode('SysvarS1otHistory11111111111111111111111111'), ignoreIfOptional: true, }, { account: /^(stakeHistorySysvar|sysvarStakeHistory)$/, defaultValue: publicKeyValueNode('SysvarStakeHistory1111111111111111111111111'), ignoreIfOptional: true, }, { account: /^(mplCoreProgram)$/, defaultValue: publicKeyValueNode('CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d', 'mplCore'), ignoreIfOptional: true, }, ]; export function setInstructionAccountDefaultValuesVisitor(rules: InstructionAccountDefaultRule[]) { const linkables = new LinkableDictionary(); const stack = new NodeStack(); // Place the rules with instructions first. const sortedRules = rules.sort((a, b) => { const ia = 'instruction' in a; const ib = 'instruction' in b; if ((ia && ib) || (!a && !ib)) return 0; return ia ? -1 : 1; }); function matchRule( instruction: InstructionNode, account: InstructionAccountNode, ): InstructionAccountDefaultRule | undefined { return sortedRules.find(rule => { if ('instruction' in rule && rule.instruction && camelCase(rule.instruction) !== instruction.name) { return false; } return typeof rule.account === 'string' ? camelCase(rule.account) === account.name : rule.account.test(account.name); }); } return pipe( nonNullableIdentityVisitor({ keys: ['rootNode', 'programNode', 'instructionNode'] }), v => extendVisitor(v, { visitInstruction(node) { const instructionPath = stack.getPath('instructionNode'); const instructionAccounts = node.accounts.map((account): InstructionAccountNode => { const rule = matchRule(node, account); if (!rule) return account; if ((rule.ignoreIfOptional ?? false) && (account.isOptional || !!account.defaultValue)) { return account; } try { return { ...account, defaultValue: visit( rule.defaultValue, fillDefaultPdaSeedValuesVisitor(instructionPath, linkables, true), ), }; } catch { return account; } }); return instructionNode({ ...node, accounts: instructionAccounts, }); }, }), v => recordNodeStackVisitor(v, stack), v => recordLinkablesOnFirstVisitVisitor(v, linkables), ); } ================================================ FILE: packages/visitors/src/setInstructionDiscriminatorsVisitor.ts ================================================ import { assertIsNode, fieldDiscriminatorNode, instructionArgumentNode, instructionNode, numberTypeNode, TypeNode, ValueNode, } from '@codama/nodes'; import { BottomUpNodeTransformerWithSelector, bottomUpTransformerVisitor } from '@codama/visitors-core'; type Discriminator = { /** @defaultValue `[]` */ docs?: string[]; /** @defaultValue `"discriminator"` */ name?: string; /** @defaultValue `"omitted"` */ strategy?: 'omitted' | 'optional'; /** @defaultValue `numberTypeNode('u8')` */ type?: TypeNode; value: ValueNode; }; export function setInstructionDiscriminatorsVisitor(map: Record) { return bottomUpTransformerVisitor( Object.entries(map).map( ([selector, discriminator]): BottomUpNodeTransformerWithSelector => ({ select: ['[instructionNode]', selector], transform: node => { assertIsNode(node, 'instructionNode'); const discriminatorArgument = instructionArgumentNode({ defaultValue: discriminator.value, defaultValueStrategy: discriminator.strategy ?? 'omitted', docs: discriminator.docs ?? [], name: discriminator.name ?? 'discriminator', type: discriminator.type ?? numberTypeNode('u8'), }); return instructionNode({ ...node, arguments: [discriminatorArgument, ...node.arguments], discriminators: [ fieldDiscriminatorNode(discriminator.name ?? 'discriminator'), ...(node.discriminators ?? []), ], }); }, }), ), ); } ================================================ FILE: packages/visitors/src/setNumberWrappersVisitor.ts ================================================ import { CODAMA_ERROR__VISITORS__INVALID_NUMBER_WRAPPER, CodamaError } from '@codama/errors'; import { amountTypeNode, assertIsNestedTypeNode, dateTimeTypeNode, solAmountTypeNode } from '@codama/nodes'; import { BottomUpNodeTransformerWithSelector, bottomUpTransformerVisitor } from '@codama/visitors-core'; export type NumberWrapper = | { decimals: number; kind: 'Amount'; unit?: string } | { kind: 'DateTime' } | { kind: 'SolAmount' }; type NumberWrapperMap = Record; export function setNumberWrappersVisitor(map: NumberWrapperMap) { return bottomUpTransformerVisitor( Object.entries(map).map( ([selectorStack, wrapper]): BottomUpNodeTransformerWithSelector => ({ select: `${selectorStack}.[numberTypeNode]`, transform: node => { assertIsNestedTypeNode(node, 'numberTypeNode'); switch (wrapper.kind) { case 'DateTime': return dateTimeTypeNode(node); case 'SolAmount': return solAmountTypeNode(node); case 'Amount': return amountTypeNode(node, wrapper.decimals, wrapper.unit); default: throw new CodamaError(CODAMA_ERROR__VISITORS__INVALID_NUMBER_WRAPPER, { wrapper }); } }, }), ), ); } ================================================ FILE: packages/visitors/src/setStructDefaultValuesVisitor.ts ================================================ import { assertIsNode, camelCase, InstructionArgumentNode, instructionArgumentNode, instructionNode, StructFieldTypeNode, structFieldTypeNode, structTypeNode, ValueNode, } from '@codama/nodes'; import { BottomUpNodeTransformerWithSelector, bottomUpTransformerVisitor } from '@codama/visitors-core'; type StructDefaultValueMap = Record>; type StructDefaultValue = ValueNode | { strategy?: 'omitted' | 'optional'; value: ValueNode } | null; export function setStructDefaultValuesVisitor(map: StructDefaultValueMap) { return bottomUpTransformerVisitor( Object.entries(map).flatMap(([stack, defaultValues]): BottomUpNodeTransformerWithSelector[] => { const camelCasedDefaultValues = Object.fromEntries( Object.entries(defaultValues).map(([key, value]) => [camelCase(key), value]), ); return [ { select: `${stack}.[structTypeNode]`, transform: node => { assertIsNode(node, 'structTypeNode'); const fields = node.fields.map((field): StructFieldTypeNode => { const defaultValue = camelCasedDefaultValues[field.name]; if (defaultValue === undefined) return field; if (defaultValue === null) { return structFieldTypeNode({ ...field, defaultValue: undefined, defaultValueStrategy: undefined, }); } return structFieldTypeNode({ ...field, defaultValue: 'kind' in defaultValue ? defaultValue : defaultValue.value, defaultValueStrategy: 'kind' in defaultValue ? undefined : defaultValue.strategy, }); }); return structTypeNode(fields); }, }, { select: ['[instructionNode]', stack], transform: node => { assertIsNode(node, 'instructionNode'); const transformArguments = (arg: InstructionArgumentNode): InstructionArgumentNode => { const defaultValue = camelCasedDefaultValues[arg.name]; if (defaultValue === undefined) return arg; if (defaultValue === null) { return instructionArgumentNode({ ...arg, defaultValue: undefined, defaultValueStrategy: undefined, }); } return instructionArgumentNode({ ...arg, defaultValue: 'kind' in defaultValue ? defaultValue : defaultValue.value, defaultValueStrategy: 'kind' in defaultValue ? undefined : defaultValue.strategy, }); }; return instructionNode({ ...node, arguments: node.arguments.map(transformArguments), extraArguments: node.extraArguments ? node.extraArguments.map(transformArguments) : undefined, }); }, }, ]; }), ); } ================================================ FILE: packages/visitors/src/transformDefinedTypesIntoAccountsVisitor.ts ================================================ import { accountNode, assertIsNode, programNode } from '@codama/nodes'; import { extendVisitor, nonNullableIdentityVisitor, pipe } from '@codama/visitors-core'; export function transformDefinedTypesIntoAccountsVisitor(definedTypes: string[]) { return pipe(nonNullableIdentityVisitor({ keys: ['rootNode', 'programNode'] }), v => extendVisitor(v, { visitProgram(program) { const typesToExtract = program.definedTypes.filter(node => definedTypes.includes(node.name)); const newDefinedTypes = program.definedTypes.filter(node => !definedTypes.includes(node.name)); const newAccounts = typesToExtract.map(node => { assertIsNode(node.type, 'structTypeNode'); return accountNode({ ...node, data: node.type, discriminators: [], size: undefined, }); }); return programNode({ ...program, accounts: [...program.accounts, ...newAccounts], definedTypes: newDefinedTypes, }); }, }), ); } ================================================ FILE: packages/visitors/src/transformU8ArraysToBytesVisitor.ts ================================================ import { ArrayTypeNode, arrayTypeNode, assertIsNode, bytesTypeNode, fixedSizeTypeNode, isNode, TYPE_NODES, } from '@codama/nodes'; import { extendVisitor, nonNullableIdentityVisitor, pipe, visit } from '@codama/visitors-core'; export function transformU8ArraysToBytesVisitor(sizes: number[] | '*' = '*') { const hasRequiredSize = (count: ArrayTypeNode['count']): boolean => { if (!isNode(count, 'fixedCountNode')) return false; return sizes === '*' || sizes.includes(count.value); }; return pipe(nonNullableIdentityVisitor(), v => extendVisitor(v, { visitArrayType(node, { self }) { const child = visit(node.item, self); assertIsNode(child, TYPE_NODES); if ( isNode(child, 'numberTypeNode') && child.format === 'u8' && isNode(node.count, 'fixedCountNode') && hasRequiredSize(node.count) ) { return fixedSizeTypeNode(bytesTypeNode(), node.count.value); } return arrayTypeNode(child, node.count); }, }), ); } ================================================ FILE: packages/visitors/src/unwrapDefinedTypesVisitor.ts ================================================ import { assertIsNodeFilter, camelCase, CamelCaseString, programNode } from '@codama/nodes'; import { extendVisitor, findProgramNodeFromPath, getLastNodeFromPath, LinkableDictionary, NodeStack, nonNullableIdentityVisitor, pipe, recordLinkablesOnFirstVisitVisitor, recordNodeStackVisitor, visit, } from '@codama/visitors-core'; export function unwrapDefinedTypesVisitor(typesToInline: string[] | '*' = '*') { const linkables = new LinkableDictionary(); const stack = new NodeStack(); const typesToInlineCamelCased = (typesToInline === '*' ? [] : typesToInline).map(fullPath => { if (!fullPath.includes('.')) return camelCase(fullPath); const [programName, typeName] = fullPath.split('.'); return `${camelCase(programName)}.${camelCase(typeName)}`; }); const shouldInline = (typeName: CamelCaseString, programName: CamelCaseString | undefined): boolean => { if (typesToInline === '*') return true; const fullPath = `${programName}.${typeName}`; if (!!programName && typesToInlineCamelCased.includes(fullPath)) return true; return typesToInlineCamelCased.includes(typeName); }; return pipe( nonNullableIdentityVisitor(), v => extendVisitor(v, { visitDefinedTypeLink(linkType, { self }) { const programName = linkType.program?.name ?? findProgramNodeFromPath(stack.getPath())?.name; if (!shouldInline(linkType.name, programName)) { return linkType; } const definedTypePath = linkables.getPathOrThrow(stack.getPath('definedTypeLinkNode')); const definedType = getLastNodeFromPath(definedTypePath); stack.pushPath(definedTypePath); const result = visit(definedType.type, self); stack.popPath(); return result; }, visitProgram(program, { self }) { return programNode({ ...program, accounts: program.accounts .map(account => visit(account, self)) .filter(assertIsNodeFilter('accountNode')), definedTypes: program.definedTypes .filter(definedType => !shouldInline(definedType.name, program.name)) .map(type => visit(type, self)) .filter(assertIsNodeFilter('definedTypeNode')), instructions: program.instructions .map(instruction => visit(instruction, self)) .filter(assertIsNodeFilter('instructionNode')), }); }, }), v => recordNodeStackVisitor(v, stack), v => recordLinkablesOnFirstVisitVisitor(v, linkables), ); } ================================================ FILE: packages/visitors/src/unwrapInstructionArgsDefinedTypesVisitor.ts ================================================ import { assertIsNode, CamelCaseString, definedTypeLinkNode, isNode } from '@codama/nodes'; import { getRecordLinkablesVisitor, LinkableDictionary, rootNodeVisitor, visit } from '@codama/visitors-core'; import { getDefinedTypeHistogramVisitor } from './getDefinedTypeHistogramVisitor'; import { unwrapDefinedTypesVisitor } from './unwrapDefinedTypesVisitor'; export function unwrapInstructionArgsDefinedTypesVisitor() { return rootNodeVisitor(root => { const histogram = visit(root, getDefinedTypeHistogramVisitor()); const linkables = new LinkableDictionary(); visit(root, getRecordLinkablesVisitor(linkables)); const definedTypesToInline = (Object.keys(histogram) as CamelCaseString[]) // Get all defined types used exactly once as an instruction argument. .filter(key => (histogram[key].total ?? 0) === 1 && (histogram[key].directlyAsInstructionArgs ?? 0) === 1) // Filter out enums which are better defined as external types. .filter(key => { const names = key.split('.'); const link = names.length == 2 ? definedTypeLinkNode(names[1], names[0]) : definedTypeLinkNode(key); const found = linkables.get([link]); return found && !isNode(found.type, 'enumTypeNode'); }); // Inline the identified defined types if any. if (definedTypesToInline.length > 0) { const inlineVisitor = unwrapDefinedTypesVisitor(definedTypesToInline); const newRoot = visit(root, inlineVisitor); assertIsNode(newRoot, 'rootNode'); return newRoot; } return root; }); } ================================================ FILE: packages/visitors/src/unwrapTupleEnumWithSingleStructVisitor.ts ================================================ import { assertIsNode, CamelCaseString, DefinedTypeNode, enumStructVariantTypeNode, getAllDefinedTypes, isNode, REGISTERED_NODE_KINDS, resolveNestedTypeNode, StructTypeNode, transformNestedTypeNode, } from '@codama/nodes'; import { bottomUpTransformerVisitor, getNodeSelectorFunction, NodeSelectorFunction, NodeStack, rootNodeVisitor, visit, } from '@codama/visitors-core'; import { getDefinedTypeHistogramVisitor } from './getDefinedTypeHistogramVisitor'; import { unwrapDefinedTypesVisitor } from './unwrapDefinedTypesVisitor'; export function unwrapTupleEnumWithSingleStructVisitor(enumsOrVariantsToUnwrap: string[] | '*' = '*') { const selectorFunctions: NodeSelectorFunction[] = enumsOrVariantsToUnwrap === '*' ? [() => true] : enumsOrVariantsToUnwrap.map(selector => getNodeSelectorFunction(selector)); const shouldUnwrap = (stack: NodeStack): boolean => selectorFunctions.some(selector => selector(stack.getPath(REGISTERED_NODE_KINDS))); return rootNodeVisitor(root => { const typesToPotentiallyUnwrap: string[] = []; const definedTypes: Map = new Map( getAllDefinedTypes(root).map(definedType => [definedType.name, definedType]), ); let newRoot = visit( root, bottomUpTransformerVisitor([ { select: '[enumTupleVariantTypeNode]', transform: (node, stack) => { assertIsNode(node, 'enumTupleVariantTypeNode'); if (!shouldUnwrap(stack)) return node; const tupleNode = resolveNestedTypeNode(node.tuple); if (tupleNode.items.length !== 1) return node; let item = tupleNode.items[0]; if (isNode(item, 'definedTypeLinkNode')) { const definedType = definedTypes.get(item.name); if (!definedType) return node; if (!isNode(definedType.type, 'structTypeNode')) return node; typesToPotentiallyUnwrap.push(item.name); item = definedType.type; } if (!isNode(item, 'structTypeNode')) return node; const nestedStruct = transformNestedTypeNode(node.tuple, () => item as StructTypeNode); return enumStructVariantTypeNode(node.name, nestedStruct); }, }, ]), ); assertIsNode(newRoot, 'rootNode'); const histogram = visit(newRoot, getDefinedTypeHistogramVisitor()); const typesToUnwrap = typesToPotentiallyUnwrap.filter( type => !histogram[type as CamelCaseString] || histogram[type as CamelCaseString].total === 0, ); newRoot = visit(newRoot, unwrapDefinedTypesVisitor(typesToUnwrap)); assertIsNode(newRoot, 'rootNode'); return newRoot; }); } ================================================ FILE: packages/visitors/src/unwrapTypeDefinedLinksVisitor.ts ================================================ import { BottomUpNodeTransformerWithSelector, bottomUpTransformerVisitor, LinkableDictionary, pipe, recordLinkablesOnFirstVisitVisitor, } from '@codama/visitors-core'; export function unwrapTypeDefinedLinksVisitor(definedLinksType: string[]) { const linkables = new LinkableDictionary(); const transformers: BottomUpNodeTransformerWithSelector[] = definedLinksType.map(selector => ({ select: ['[definedTypeLinkNode]', selector], transform: (_, stack) => { const definedType = linkables.getOrThrow(stack.getPath('definedTypeLinkNode')); return definedType.type; }, })); return pipe(bottomUpTransformerVisitor(transformers), v => recordLinkablesOnFirstVisitVisitor(v, linkables)); } ================================================ FILE: packages/visitors/src/updateAccountsVisitor.ts ================================================ import { accountLinkNode, accountNode, AccountNodeInput, assertIsNode, camelCase, CamelCaseString, pdaLinkNode, PdaNode, pdaNode, PdaSeedNode, programNode, transformNestedTypeNode, } from '@codama/nodes'; import { BottomUpNodeTransformerWithSelector, bottomUpTransformerVisitor, findProgramNodeFromPath, } from '@codama/visitors-core'; import { renameStructNode } from './renameHelpers'; export type AccountUpdates = | { delete: true } | (Partial> & { data?: Record; seeds?: PdaSeedNode[]; }); export function updateAccountsVisitor(map: Record) { return bottomUpTransformerVisitor( Object.entries(map).flatMap(([selector, updates]) => { const newName = typeof updates === 'object' && 'name' in updates && updates.name ? camelCase(updates.name) : undefined; const pdasToUpsert = [] as { pda: PdaNode; program: CamelCaseString }[]; const transformers: BottomUpNodeTransformerWithSelector[] = [ { select: ['[accountNode]', selector], transform: (node, stack) => { assertIsNode(node, 'accountNode'); if ('delete' in updates) return null; const programNode = findProgramNodeFromPath(stack.getPath())!; const { seeds, pda, ...assignableUpdates } = updates; let newPda = node.pda; if (pda && seeds !== undefined) { newPda = pda; pdasToUpsert.push({ pda: pdaNode({ name: pda.name, seeds }), program: programNode.name, }); } else if (pda) { newPda = pda; } else if (seeds !== undefined && node.pda) { pdasToUpsert.push({ pda: pdaNode({ name: node.pda.name, seeds }), program: programNode.name, }); } else if (seeds !== undefined) { newPda = pdaLinkNode(newName ?? node.name); pdasToUpsert.push({ pda: pdaNode({ name: newName ?? node.name, seeds }), program: programNode.name, }); } return accountNode({ ...node, ...assignableUpdates, data: transformNestedTypeNode(node.data, struct => renameStructNode(struct, updates.data ?? {}), ), pda: newPda, }); }, }, { select: `[programNode]`, transform: node => { assertIsNode(node, 'programNode'); const pdasToUpsertForProgram = pdasToUpsert .filter(p => p.program === node.name) .map(p => p.pda); if (pdasToUpsertForProgram.length === 0) return node; const existingPdaNames = new Set(node.pdas.map(pda => pda.name)); const pdasToCreate = pdasToUpsertForProgram.filter(p => !existingPdaNames.has(p.name)); const pdasToUpdate = new Map( pdasToUpsertForProgram.filter(p => existingPdaNames.has(p.name)).map(p => [p.name, p]), ); const newPdas = [...node.pdas.map(p => pdasToUpdate.get(p.name) ?? p), ...pdasToCreate]; return programNode({ ...node, pdas: newPdas }); }, }, ]; if (newName) { transformers.push( { select: ['[accountLinkNode]', selector], transform: node => { assertIsNode(node, 'accountLinkNode'); return accountLinkNode(newName); }, }, { select: ['[pdaNode]', selector], transform: node => { assertIsNode(node, 'pdaNode'); return pdaNode({ name: newName, seeds: node.seeds }); }, }, { select: ['[pdaLinkNode]', selector], transform: node => { assertIsNode(node, 'pdaLinkNode'); return pdaLinkNode(newName); }, }, ); } return transformers; }), ); } ================================================ FILE: packages/visitors/src/updateDefinedTypesVisitor.ts ================================================ import { assertIsNode, camelCase, definedTypeLinkNode, definedTypeNode, DefinedTypeNodeInput, isNode, } from '@codama/nodes'; import { BottomUpNodeTransformerWithSelector, bottomUpTransformerVisitor } from '@codama/visitors-core'; import { renameEnumNode, renameStructNode } from './renameHelpers'; export type DefinedTypeUpdates = | { delete: true } | (Partial> & { data?: Record; }); export function updateDefinedTypesVisitor(map: Record) { return bottomUpTransformerVisitor( Object.entries(map).flatMap(([selector, updates]): BottomUpNodeTransformerWithSelector[] => { const newName = typeof updates === 'object' && 'name' in updates && updates.name ? camelCase(updates.name) : undefined; const transformers: BottomUpNodeTransformerWithSelector[] = [ { select: ['[definedTypeNode]', selector], transform: node => { assertIsNode(node, 'definedTypeNode'); if ('delete' in updates) { return null; } const { data: dataUpdates, ...otherUpdates } = updates; let newType = node.type; if (isNode(node.type, 'structTypeNode')) { newType = renameStructNode(node.type, dataUpdates ?? {}); } else if (isNode(node.type, 'enumTypeNode')) { newType = renameEnumNode(node.type, dataUpdates ?? {}); } return definedTypeNode({ ...node, ...otherUpdates, name: newName ?? node.name, type: newType, }); }, }, ]; if (newName) { transformers.push({ select: ['[definedTypeLinkNode]', selector], transform: node => { assertIsNode(node, 'definedTypeLinkNode'); return definedTypeLinkNode(newName); }, }); } return transformers; }), ); } ================================================ FILE: packages/visitors/src/updateErrorsVisitor.ts ================================================ import { assertIsNode, errorNode, ErrorNodeInput } from '@codama/nodes'; import { BottomUpNodeTransformerWithSelector, bottomUpTransformerVisitor } from '@codama/visitors-core'; export type ErrorUpdates = Partial | { delete: true }; export function updateErrorsVisitor(map: Record) { return bottomUpTransformerVisitor( Object.entries(map).map( ([name, updates]): BottomUpNodeTransformerWithSelector => ({ select: `[errorNode]${name}`, transform: node => { assertIsNode(node, 'errorNode'); if ('delete' in updates) return null; return errorNode({ ...node, ...updates }); }, }), ), ); } ================================================ FILE: packages/visitors/src/updateInstructionsVisitor.ts ================================================ import { assertIsNode, InstructionAccountNode, instructionAccountNode, InstructionAccountNodeInput, InstructionArgumentNode, instructionArgumentNode, InstructionArgumentNodeInput, InstructionInputValueNode, InstructionNode, instructionNode, InstructionNodeInput, TYPE_NODES, } from '@codama/nodes'; import { BottomUpNodeTransformerWithSelector, bottomUpTransformerVisitor, LinkableDictionary, NodePath, NodeStack, pipe, recordLinkablesOnFirstVisitVisitor, recordNodeStackVisitor, visit, } from '@codama/visitors-core'; import { fillDefaultPdaSeedValuesVisitor } from './fillDefaultPdaSeedValuesVisitor'; export type InstructionUpdates = | Partial< Omit & { accounts?: InstructionAccountUpdates; arguments?: InstructionArgumentUpdates; } > | { delete: true }; export type InstructionAccountUpdates = Record< string, Partial> & { defaultValue?: InstructionInputValueNode | null; } >; export type InstructionArgumentUpdates = Record< string, Partial> & { defaultValue?: InstructionInputValueNode | null; } >; export function updateInstructionsVisitor(map: Record) { const linkables = new LinkableDictionary(); const stack = new NodeStack(); const transformers = Object.entries(map).map( ([selector, updates]): BottomUpNodeTransformerWithSelector => ({ select: ['[instructionNode]', selector], transform: node => { assertIsNode(node, 'instructionNode'); if ('delete' in updates) { return null; } const instructionPath = stack.getPath('instructionNode'); const { accounts: accountUpdates, arguments: argumentUpdates, ...metadataUpdates } = updates; const { newArguments, newExtraArguments } = handleInstructionArguments(node, argumentUpdates ?? {}); const newAccounts = node.accounts.map(account => handleInstructionAccount(instructionPath, account, accountUpdates ?? {}, linkables), ); return instructionNode({ ...node, ...metadataUpdates, accounts: newAccounts, arguments: newArguments, extraArguments: newExtraArguments.length > 0 ? newExtraArguments : undefined, }); }, }), ); return pipe( bottomUpTransformerVisitor(transformers), v => recordNodeStackVisitor(v, stack), v => recordLinkablesOnFirstVisitVisitor(v, linkables), ); } function handleInstructionAccount( instructionPath: NodePath, account: InstructionAccountNode, accountUpdates: InstructionAccountUpdates, linkables: LinkableDictionary, ): InstructionAccountNode { const accountUpdate = accountUpdates?.[account.name]; if (!accountUpdate) return account; const { defaultValue, ...acountWithoutDefault } = { ...account, ...accountUpdate, }; if (!defaultValue) { return instructionAccountNode(acountWithoutDefault); } return instructionAccountNode({ ...acountWithoutDefault, defaultValue: visit(defaultValue, fillDefaultPdaSeedValuesVisitor(instructionPath, linkables)), }); } function handleInstructionArguments( instruction: InstructionNode, argUpdates: InstructionArgumentUpdates, ): { newArguments: InstructionArgumentNode[]; newExtraArguments: InstructionArgumentNode[]; } { const usedArguments = new Set(); const newArguments = instruction.arguments.map(node => { const argUpdate = argUpdates[node.name]; if (!argUpdate) return node; usedArguments.add(node.name); return instructionArgumentNode({ ...node, defaultValue: argUpdate.defaultValue ?? node.defaultValue, defaultValueStrategy: argUpdate.defaultValueStrategy ?? node.defaultValueStrategy, docs: argUpdate.docs ?? node.docs, name: argUpdate.name ?? node.name, type: argUpdate.type ?? node.type, }); }); const updatedExtraArguments = (instruction.extraArguments ?? []).map(node => { if (usedArguments.has(node.name)) return node; const argUpdate = argUpdates[node.name]; if (!argUpdate) return node; usedArguments.add(node.name); return instructionArgumentNode({ ...node, defaultValue: argUpdate.defaultValue ?? node.defaultValue, defaultValueStrategy: argUpdate.defaultValueStrategy ?? node.defaultValueStrategy, docs: argUpdate.docs ?? node.docs, name: argUpdate.name ?? node.name, type: argUpdate.type ?? node.type, }); }); const newExtraArguments = [ ...updatedExtraArguments, ...Object.entries(argUpdates) .filter(([argName]) => !usedArguments.has(argName)) .map(([argName, argUpdate]) => { const { type } = argUpdate; assertIsNode(type, TYPE_NODES); return instructionArgumentNode({ defaultValue: argUpdate.defaultValue ?? undefined, defaultValueStrategy: argUpdate.defaultValueStrategy ?? undefined, docs: argUpdate.docs ?? [], name: argUpdate.name ?? argName, type, }); }), ]; return { newArguments, newExtraArguments }; } ================================================ FILE: packages/visitors/src/updateProgramsVisitor.ts ================================================ import { assertIsNode, camelCase, programLinkNode, programNode, ProgramNodeInput } from '@codama/nodes'; import { BottomUpNodeTransformerWithSelector, bottomUpTransformerVisitor } from '@codama/visitors-core'; export type ProgramUpdates = | Partial> | { delete: true }; export function updateProgramsVisitor(map: Record) { return bottomUpTransformerVisitor( Object.entries(map).flatMap(([name, updates]): BottomUpNodeTransformerWithSelector[] => { const newName = typeof updates === 'object' && 'name' in updates && updates.name ? camelCase(updates.name) : undefined; const transformers: BottomUpNodeTransformerWithSelector[] = [ { select: `[programNode]${name}`, transform: node => { assertIsNode(node, 'programNode'); if ('delete' in updates) return null; return programNode({ ...node, ...updates }); }, }, ]; if (newName) { transformers.push({ select: `[programLinkNode]${name}`, transform: node => { assertIsNode(node, 'programLinkNode'); return programLinkNode(newName); }, }); } return transformers; }), ); } ================================================ FILE: packages/visitors/test/addPdasVisitor.test.ts ================================================ import { CODAMA_ERROR__VISITORS__CANNOT_ADD_DUPLICATED_PDA_NAMES, CodamaError } from '@codama/errors'; import { constantPdaSeedNodeFromProgramId, constantPdaSeedNodeFromString, pdaNode, programNode, publicKeyTypeNode, variablePdaSeedNode, } from '@codama/nodes'; import { visit } from '@codama/visitors-core'; import { expect, test } from 'vitest'; import { addPdasVisitor } from '../src'; test('it adds PDA nodes to a program', () => { // Given a program with a single PDA. const node = programNode({ name: 'myProgram', pdas: [ pdaNode({ name: 'associatedToken', seeds: [ variablePdaSeedNode('owner', publicKeyTypeNode()), constantPdaSeedNodeFromProgramId(), variablePdaSeedNode('mint', publicKeyTypeNode()), ], }), ], publicKey: 'Epo9rxh99jpeeWabRZi4tpgUVxZQeVn9vbbDjUztJtu4', }); // When we add two more PDAs. const newPdas = [ pdaNode({ name: 'metadata', seeds: [ constantPdaSeedNodeFromString('utf8', 'metadata'), constantPdaSeedNodeFromProgramId(), variablePdaSeedNode('mint', publicKeyTypeNode()), ], }), pdaNode({ name: 'masterEdition', seeds: [ constantPdaSeedNodeFromString('utf8', 'metadata'), constantPdaSeedNodeFromProgramId(), variablePdaSeedNode('mint', publicKeyTypeNode()), constantPdaSeedNodeFromString('utf8', 'edition'), ], }), ]; const result = visit(node, addPdasVisitor({ myProgram: newPdas })); // Then we expect the following program to be returned. expect(result).toEqual({ ...node, pdas: [...node.pdas, ...newPdas] }); }); test('it fails to add a PDA if its name conflicts with an existing PDA on the program', () => { // Given a program with a PDA named "myPda". const node = programNode({ name: 'myProgram', pdas: [ pdaNode({ name: 'myPda', seeds: [ variablePdaSeedNode('owner', publicKeyTypeNode()), constantPdaSeedNodeFromProgramId(), variablePdaSeedNode('mint', publicKeyTypeNode()), ], }), ], publicKey: 'Epo9rxh99jpeeWabRZi4tpgUVxZQeVn9vbbDjUztJtu4', }); // When we try to add another PDA with the same name. const fn = () => visit( node, addPdasVisitor({ myProgram: [ pdaNode({ name: 'myPda', seeds: [ constantPdaSeedNodeFromString('utf8', 'metadata'), constantPdaSeedNodeFromProgramId(), variablePdaSeedNode('mint', publicKeyTypeNode()), ], }), ], }), ); // Then we expect the following error to be thrown. expect(fn).toThrow( new CodamaError(CODAMA_ERROR__VISITORS__CANNOT_ADD_DUPLICATED_PDA_NAMES, { duplicatedPdaNames: ['myPda'], program: node, programName: 'myProgram', }), ); }); test('it adds PDA nodes to a program with docs', () => { // Given a program with a single PDA. const node = programNode({ name: 'myProgram', pdas: [ pdaNode({ name: 'associatedToken', seeds: [ variablePdaSeedNode('owner', publicKeyTypeNode()), constantPdaSeedNodeFromProgramId(), variablePdaSeedNode('mint', publicKeyTypeNode()), ], }), ], publicKey: 'Epo9rxh99jpeeWabRZi4tpgUVxZQeVn9vbbDjUztJtu4', }); // When we add two more PDAs. const newPdas = [ pdaNode({ docs: 'Metadata for a token.', name: 'metadata', seeds: [ constantPdaSeedNodeFromString('utf8', 'metadata'), constantPdaSeedNodeFromProgramId(), variablePdaSeedNode('mint', publicKeyTypeNode()), ], }), pdaNode({ docs: 'The master edition.', name: 'masterEdition', seeds: [ constantPdaSeedNodeFromString('utf8', 'metadata'), constantPdaSeedNodeFromProgramId(), variablePdaSeedNode('mint', publicKeyTypeNode()), constantPdaSeedNodeFromString('utf8', 'edition'), ], }), ]; const result = visit(node, addPdasVisitor({ myProgram: newPdas })); // Then we expect the following program to be returned. expect(result).toEqual({ ...node, pdas: [...node.pdas, ...newPdas] }); }); ================================================ FILE: packages/visitors/test/fillDefaultPdaSeedValuesVisitor.test.ts ================================================ import { accountValueNode, argumentValueNode, conditionalValueNode, instructionAccountNode, instructionArgumentNode, instructionNode, numberTypeNode, numberValueNode, pdaNode, pdaSeedValueNode, pdaValueNode, programNode, publicKeyTypeNode, variablePdaSeedNode, } from '@codama/nodes'; import { LinkableDictionary, visit } from '@codama/visitors-core'; import { expect, test } from 'vitest'; import { fillDefaultPdaSeedValuesVisitor } from '../src'; test('it fills missing pda seed values with default values', () => { // Given a pdaNode with three variable seeds. const program = programNode({ name: 'myProgram', pdas: [ pdaNode({ name: 'myPda', seeds: [ variablePdaSeedNode('seed1', numberTypeNode('u64')), variablePdaSeedNode('seed2', numberTypeNode('u64')), variablePdaSeedNode('seed3', publicKeyTypeNode()), ], }), ], publicKey: '1111', }); const pda = program.pdas[0]; // And a linkable dictionary that recorded this PDA. const linkables = new LinkableDictionary(); linkables.recordPath([program, pda]); // And a pdaValueNode with a single seed filled. const node = pdaValueNode('myPda', [pdaSeedValueNode('seed1', numberValueNode(42))]); // And an instruction node that defines both of the missing seeds. const instruction = instructionNode({ accounts: [ instructionAccountNode({ isSigner: false, isWritable: false, name: 'seed3', }), ], arguments: [instructionArgumentNode({ name: 'seed2', type: numberTypeNode('u64') })], name: 'myInstruction', }); // When we fill the PDA seeds with default values. const result = visit(node, fillDefaultPdaSeedValuesVisitor([program, instruction], linkables)); // Then we expect the following pdaValueNode to be returned. expect(result).toEqual( pdaValueNode('myPda', [ pdaSeedValueNode('seed1', numberValueNode(42)), pdaSeedValueNode('seed2', argumentValueNode('seed2')), pdaSeedValueNode('seed3', accountValueNode('seed3')), ]), ); }); test('it fills nested pda value nodes', () => { // Given a pdaNode with three variable seeds. const program = programNode({ name: 'myProgram', pdas: [ pdaNode({ name: 'myPda', seeds: [ variablePdaSeedNode('seed1', numberTypeNode('u64')), variablePdaSeedNode('seed2', numberTypeNode('u64')), variablePdaSeedNode('seed3', publicKeyTypeNode()), ], }), ], publicKey: '1111', }); const pda = program.pdas[0]; // And a linkable dictionary that recorded this PDA. const linkables = new LinkableDictionary(); linkables.recordPath([program, pda]); // And a pdaValueNode nested inside a conditionalValueNode. const node = conditionalValueNode({ condition: accountValueNode('myAccount'), ifTrue: pdaValueNode('myPda', [pdaSeedValueNode('seed1', numberValueNode(42))]), }); // And an instruction node that defines both of the missing seeds. const instruction = instructionNode({ accounts: [ instructionAccountNode({ isSigner: false, isWritable: false, name: 'seed3', }), ], arguments: [instructionArgumentNode({ name: 'seed2', type: numberTypeNode('u64') })], name: 'myInstruction', }); // When we fill the PDA seeds with default values. const result = visit(node, fillDefaultPdaSeedValuesVisitor([program, instruction], linkables)); // Then we expect the following conditionalValueNode to be returned. expect(result).toEqual( conditionalValueNode({ condition: accountValueNode('myAccount'), ifTrue: pdaValueNode('myPda', [ pdaSeedValueNode('seed1', numberValueNode(42)), pdaSeedValueNode('seed2', argumentValueNode('seed2')), pdaSeedValueNode('seed3', accountValueNode('seed3')), ]), }), ); }); test('it ignores default seeds missing from the instruction', () => { // Given a pdaNode with three variable seeds. const program = programNode({ name: 'myProgram', pdas: [ pdaNode({ name: 'myPda', seeds: [ variablePdaSeedNode('seed1', numberTypeNode('u64')), variablePdaSeedNode('seed2', numberTypeNode('u64')), variablePdaSeedNode('seed3', publicKeyTypeNode()), ], }), ], publicKey: '1111', }); const pda = program.pdas[0]; // And a linkable dictionary that recorded this PDA. const linkables = new LinkableDictionary(); linkables.recordPath([program, pda]); // And a pdaValueNode with a single seed filled. const node = pdaValueNode('myPda', [pdaSeedValueNode('seed1', numberValueNode(42))]); // And an instruction node that defines only seed2 as an argument. const instruction = instructionNode({ arguments: [instructionArgumentNode({ name: 'seed2', type: numberTypeNode('u64') })], name: 'myInstruction', }); // When we fill the PDA seeds with default values. const result = visit(node, fillDefaultPdaSeedValuesVisitor([program, instruction], linkables)); // Then we expect the following pdaValueNode to be returned. expect(result).toEqual( pdaValueNode('myPda', [ pdaSeedValueNode('seed1', numberValueNode(42)), pdaSeedValueNode('seed2', argumentValueNode('seed2')), ]), ); }); ================================================ FILE: packages/visitors/test/getDefinedTypeHistogramVisitor.test.ts ================================================ import { accountNode, definedTypeLinkNode, definedTypeNode, enumTypeNode, eventNode, instructionArgumentNode, instructionNode, numberTypeNode, programNode, rootNode, structFieldTypeNode, structTypeNode, } from '@codama/nodes'; import { visit } from '@codama/visitors-core'; import { expect, test } from 'vitest'; import { getDefinedTypeHistogramVisitor } from '../src'; test('it counts the amount of times defined types are used within the tree', () => { // Given the following tree. const node = programNode({ accounts: [ accountNode({ data: structTypeNode([ structFieldTypeNode({ name: 'field1', type: definedTypeLinkNode('myStruct'), }), structFieldTypeNode({ name: 'field2', type: definedTypeLinkNode('myEnum'), }), ]), name: 'myAccount', }), ], definedTypes: [ definedTypeNode({ name: 'myStruct', type: structTypeNode([]), }), definedTypeNode({ name: 'myEnum', type: enumTypeNode([]), }), ], errors: [], instructions: [ instructionNode({ accounts: [], arguments: [ instructionArgumentNode({ name: 'arg1', type: definedTypeLinkNode('myStruct'), }), ], name: 'myInstruction', }), ], name: 'customProgram', publicKey: '1111', version: '1.0.0', }); // When we get its defined type histogram. const histogram = visit(node, getDefinedTypeHistogramVisitor()); // Then we expect the following histogram. expect(histogram).toEqual({ 'customProgram.myEnum': { directlyAsInstructionArgs: 0, inAccounts: 1, inDefinedTypes: 0, inEvents: 0, inInstructionArgs: 0, total: 1, }, 'customProgram.myStruct': { directlyAsInstructionArgs: 1, inAccounts: 1, inDefinedTypes: 0, inEvents: 0, inInstructionArgs: 1, total: 2, }, }); }); test('it counts defined types used inside event payloads', () => { const node = programNode({ definedTypes: [definedTypeNode({ name: 'eventPayload', type: structTypeNode([]) })], events: [ eventNode({ data: structTypeNode([ structFieldTypeNode({ name: 'payload', type: definedTypeLinkNode('eventPayload'), }), ]), name: 'payloadCreated', }), ], name: 'customProgram', publicKey: '1111', }); const histogram = visit(node, getDefinedTypeHistogramVisitor()); expect(histogram).toEqual({ 'customProgram.eventPayload': { directlyAsInstructionArgs: 0, inAccounts: 0, inDefinedTypes: 0, inEvents: 1, inInstructionArgs: 0, total: 1, }, }); }); test('it counts links from different programs separately', () => { // Given a program node with a defined type used in another type. const programA = programNode({ definedTypes: [ definedTypeNode({ name: 'myType', type: numberTypeNode('u8') }), definedTypeNode({ name: 'myCopyType', type: definedTypeLinkNode('myType') }), ], name: 'programA', publicKey: '1111', }); // And another program with a defined type sharing the same name. const programB = programNode({ definedTypes: [ definedTypeNode({ name: 'myType', type: numberTypeNode('u16') }), definedTypeNode({ name: 'myCopyType', type: definedTypeLinkNode('myType') }), ], name: 'programB', publicKey: '2222', }); // When we unwrap the defined type from programA. const node = rootNode(programA, [programB]); const histogram = visit(node, getDefinedTypeHistogramVisitor()); // Then we expect programA to have been modified but not programB. expect(histogram).toStrictEqual({ 'programA.myType': { directlyAsInstructionArgs: 0, inAccounts: 0, inDefinedTypes: 1, inEvents: 0, inInstructionArgs: 0, total: 1, }, 'programB.myType': { directlyAsInstructionArgs: 0, inAccounts: 0, inDefinedTypes: 1, inEvents: 0, inInstructionArgs: 0, total: 1, }, }); }); ================================================ FILE: packages/visitors/test/setStructDefaultValuesVisitor.test.ts ================================================ import { accountNode, assertIsNode, definedTypeNode, instructionArgumentNode, instructionNode, noneValueNode, numberTypeNode, numberValueNode, optionTypeNode, publicKeyTypeNode, resolveNestedTypeNode, structFieldTypeNode, structTypeNode, } from '@codama/nodes'; import { visit } from '@codama/visitors-core'; import { expect, test } from 'vitest'; import { setStructDefaultValuesVisitor } from '../src'; test('it adds new default values to struct fields', () => { // Given the following person type with no default values. const node = definedTypeNode({ name: 'person', type: structTypeNode([ structFieldTypeNode({ name: 'age', type: numberTypeNode('u32'), }), structFieldTypeNode({ name: 'dateOfBirth', type: optionTypeNode(numberTypeNode('i64')), }), ]), }); // When we set default values for the age and dateOfBirth fields of the person type. const result = visit( node, setStructDefaultValuesVisitor({ person: { age: numberValueNode(42), dateOfBirth: noneValueNode(), }, }), ); // Then we expect the following tree changes. assertIsNode(result, 'definedTypeNode'); assertIsNode(result.type, 'structTypeNode'); expect(result.type.fields[0].defaultValue).toEqual(numberValueNode(42)); expect(result.type.fields[0].defaultValueStrategy).toBeUndefined(); expect(result.type.fields[1].defaultValue).toEqual(noneValueNode()); expect(result.type.fields[1].defaultValueStrategy).toBeUndefined(); }); test('it adds new default values with custom strategies to struct fields', () => { // Given the following token account with no default values. const node = accountNode({ data: structTypeNode([ structFieldTypeNode({ name: 'discriminator', type: numberTypeNode('u8'), }), structFieldTypeNode({ name: 'delegateAuthority', type: optionTypeNode(publicKeyTypeNode()), }), ]), name: 'token', }); // When we set default values of that account with custom strategies. const result = visit( node, setStructDefaultValuesVisitor({ token: { delegateAuthority: { strategy: 'optional', value: noneValueNode() }, discriminator: { strategy: 'omitted', value: numberValueNode(42) }, }, }), ); // Then we expect the following tree changes. assertIsNode(result, 'accountNode'); const data = resolveNestedTypeNode(result.data); expect(data.fields[0].defaultValue).toEqual(numberValueNode(42)); expect(data.fields[0].defaultValueStrategy).toBe('omitted'); expect(data.fields[1].defaultValue).toEqual(noneValueNode()); expect(data.fields[1].defaultValueStrategy).toBe('optional'); }); test('it adds new default values to instruction arguments', () => { // Given the following instruction node with no default values for its arguments const node = instructionNode({ arguments: [ instructionArgumentNode({ name: 'discriminator', type: numberTypeNode('u8'), }), instructionArgumentNode({ name: 'amount', type: numberTypeNode('u64'), }), ], name: 'transferTokens', }); // When we set default values for its arguments. const result = visit( node, setStructDefaultValuesVisitor({ transferTokens: { amount: numberValueNode(1), discriminator: { strategy: 'omitted', value: numberValueNode(42) }, }, }), ); // Then we expect the following tree changes. assertIsNode(result, 'instructionNode'); expect(result.arguments[0].defaultValue).toEqual(numberValueNode(42)); expect(result.arguments[0].defaultValueStrategy).toBe('omitted'); expect(result.arguments[1].defaultValue).toEqual(numberValueNode(1)); expect(result.arguments[1].defaultValueStrategy).toBeUndefined(); }); ================================================ FILE: packages/visitors/test/unwrapDefinedTypesVisitor.test.ts ================================================ import { accountNode, assertIsNode, definedTypeLinkNode, definedTypeNode, numberTypeNode, programLinkNode, programNode, rootNode, structFieldTypeNode, structTypeNode, } from '@codama/nodes'; import { visit } from '@codama/visitors-core'; import { expect, test } from 'vitest'; import { unwrapDefinedTypesVisitor } from '../src'; test('it unwraps defined types by following links', () => { // Given a program node with an account that uses a defined type link. const node = programNode({ accounts: [ accountNode({ data: structTypeNode([structFieldTypeNode({ name: 'value', type: definedTypeLinkNode('myType') })]), name: 'myAccount', }), ], definedTypes: [definedTypeNode({ name: 'myType', type: numberTypeNode('u64') })], name: 'myProgram', publicKey: '1111', }); // When we unwrap the defined types. const result = visit(node, unwrapDefinedTypesVisitor(['myType'])); // Then we expect the following tree. assertIsNode(result, 'programNode'); expect(result.accounts[0].data).toStrictEqual( structTypeNode([structFieldTypeNode({ name: 'value', type: numberTypeNode('u64') })]), ); }); test('it follows linked nodes using the correct paths', () => { // Given two link nodes designed so that the path would // fail if we did not save and restored linked paths. const programA = programNode({ definedTypes: [ definedTypeNode({ name: 'typeA', type: definedTypeLinkNode('typeB1', programLinkNode('programB')), }), ], name: 'programA', publicKey: '1111', }); const programB = programNode({ definedTypes: [ definedTypeNode({ name: 'typeB1', type: definedTypeLinkNode('typeB2') }), definedTypeNode({ name: 'typeB2', type: numberTypeNode('u64') }), ], name: 'programB', publicKey: '2222', }); const root = rootNode(programA, [programB]); // When we unwrap the defined types in programB. const visitor = unwrapDefinedTypesVisitor(['typeB1', 'typeB2']); const result = visit(root, visitor); // Then we expect the final linkable to be resolved in programA. assertIsNode(result, 'rootNode'); expect(result.program.definedTypes[0]).toStrictEqual( definedTypeNode({ name: 'typeA', type: numberTypeNode('u64') }), ); }); test('it does not unwrap types from the wrong programs', () => { // Given a program node with a defined type used in another type. const programA = programNode({ definedTypes: [ definedTypeNode({ name: 'myType', type: numberTypeNode('u8') }), definedTypeNode({ name: 'myCopyType', type: definedTypeLinkNode('myType') }), ], name: 'programA', publicKey: '1111', }); // And another program with a defined type sharing the same name. const programB = programNode({ definedTypes: [ definedTypeNode({ name: 'myType', type: numberTypeNode('u16') }), definedTypeNode({ name: 'myCopyType', type: definedTypeLinkNode('myType') }), ], name: 'programB', publicKey: '2222', }); // When we unwrap the defined type from programA. const node = rootNode(programA, [programB]); const result = visit(node, unwrapDefinedTypesVisitor(['programA.myType'])); // Then we expect programA to have been modified but not programB. assertIsNode(result, 'rootNode'); expect(result).toStrictEqual( rootNode( programNode({ definedTypes: [definedTypeNode({ name: 'myCopyType', type: numberTypeNode('u8') })], name: 'programA', publicKey: '1111', }), [programB], ), ); }); ================================================ FILE: packages/visitors/test/unwrapInstructionArgsDefinedTypesVisitor.test.ts ================================================ import { arrayTypeNode, definedTypeLinkNode, definedTypeNode, fixedCountNode, instructionArgumentNode, instructionNode, numberTypeNode, programNode, rootNode, structFieldTypeNode, structTypeNode, } from '@codama/nodes'; import { visit } from '@codama/visitors-core'; import { expect, test } from 'vitest'; import { unwrapInstructionArgsDefinedTypesVisitor } from '../src'; test('it unwraps defined type link nodes used as instruction arguments', () => { // Given a program with a type used only once as a direct instruction argument. const node = rootNode( programNode({ definedTypes: [ definedTypeNode({ name: 'typeA', type: structTypeNode([structFieldTypeNode({ name: 'foo', type: numberTypeNode('u8') })]), }), definedTypeNode({ name: 'typeB', type: structTypeNode([structFieldTypeNode({ name: 'bar', type: numberTypeNode('u8') })]), }), ], instructions: [ instructionNode({ arguments: [instructionArgumentNode({ name: 'argA', type: definedTypeLinkNode('typeA') })], name: 'myInstruction', }), ], name: 'MyProgram', publicKey: '1111', }), ); // When the defined type link nodes are unwrapped. const result = visit(node, unwrapInstructionArgsDefinedTypesVisitor()); // Then we expect the following node. expect(result).toStrictEqual( rootNode( programNode({ definedTypes: [ definedTypeNode({ name: 'typeB', type: structTypeNode([structFieldTypeNode({ name: 'bar', type: numberTypeNode('u8') })]), }), ], instructions: [ instructionNode({ arguments: [ instructionArgumentNode({ name: 'argA', type: structTypeNode([ structFieldTypeNode({ name: 'foo', type: numberTypeNode('u8') }), ]), }), ], name: 'myInstruction', }), ], name: 'MyProgram', publicKey: '1111', }), ), ); }); test('it does not unwrap defined type link nodes that are used in more than one place.', () => { // Given a link node used in an instruction argument and in another place. const node = rootNode( programNode({ definedTypes: [ definedTypeNode({ name: 'myType', type: structTypeNode([structFieldTypeNode({ name: 'foo', type: numberTypeNode('u8') })]), }), definedTypeNode({ name: 'myCopyType', type: definedTypeLinkNode('myType') }), ], instructions: [ instructionNode({ arguments: [instructionArgumentNode({ name: 'myArg', type: definedTypeLinkNode('myType') })], name: 'myInstruction', }), ], name: 'MyProgram', publicKey: '1111', }), ); // When we try to unwrap defined type link nodes for instruction arguments. const result = visit(node, unwrapInstructionArgsDefinedTypesVisitor()); // Then we expect the same node. expect(result).toStrictEqual(node); }); test('it only unwraps defined type link nodes if they are direct instruction arguments', () => { // Given a link node used in an instruction argument but not as a direct argument. const node = rootNode( programNode({ definedTypes: [ definedTypeNode({ name: 'myType', type: structTypeNode([structFieldTypeNode({ name: 'foo', type: numberTypeNode('u8') })]), }), ], instructions: [ instructionNode({ arguments: [ instructionArgumentNode({ name: 'myArg', type: arrayTypeNode(definedTypeLinkNode('myType'), fixedCountNode(3)), }), ], name: 'myInstruction', }), ], name: 'MyProgram', publicKey: '1111', }), ); // When we try to unwrap defined type link nodes for instruction arguments. const result = visit(node, unwrapInstructionArgsDefinedTypesVisitor()); // Then we expect the same node. expect(result).toStrictEqual(node); }); test('it does not unwrap defined type link nodes from other programs', () => { // Given a program that defines the const programA = programNode({ definedTypes: [definedTypeNode({ name: 'myType', type: numberTypeNode('u8') })], instructions: [ instructionNode({ arguments: [instructionArgumentNode({ name: 'myArg', type: definedTypeLinkNode('myType') })], name: 'myInstruction', }), ], name: 'programA', publicKey: '1111', }); // And another program with a defined type sharing the same name. const programB = programNode({ definedTypes: [ definedTypeNode({ name: 'myType', type: numberTypeNode('u16') }), definedTypeNode({ name: 'myCopyType', type: definedTypeLinkNode('myType') }), ], name: 'programB', publicKey: '2222', }); // When we unwrap defined type link nodes for instruction arguments for both of them. const node = rootNode(programA, [programB]); const result = visit(node, unwrapInstructionArgsDefinedTypesVisitor()); // Then we expect program A to have been modified but not program B. expect(result).toStrictEqual( rootNode( programNode({ instructions: [ instructionNode({ arguments: [instructionArgumentNode({ name: 'myArg', type: numberTypeNode('u8') })], name: 'myInstruction', }), ], name: 'programA', publicKey: '1111', }), [programB], ), ); }); ================================================ FILE: packages/visitors/test/updateAccountsVisitor.test.ts ================================================ import { accountNode, assertIsNode, CamelCaseString, constantPdaSeedNodeFromString, numberTypeNode, pdaLinkNode, pdaNode, programNode, resolveNestedTypeNode, rootNode, structFieldTypeNode, structTypeNode, } from '@codama/nodes'; import { visit } from '@codama/visitors-core'; import { expect, test } from 'vitest'; import { updateAccountsVisitor } from '../src'; test('it updates the name of an account', () => { // Given the following program node with one account. const node = programNode({ accounts: [accountNode({ name: 'myAccount' })], name: 'myProgram', publicKey: '1111', }); // When we update the name of that account. const result = visit( node, updateAccountsVisitor({ myAccount: { name: 'myNewAccount' }, }), ); // Then we expect the following tree changes. assertIsNode(result, 'programNode'); expect(result.accounts[0].name).toBe('myNewAccount' as CamelCaseString); }); test('it updates the name of an account within a specific program', () => { // Given two programs each with an account of the same name. const node = rootNode( programNode({ accounts: [accountNode({ name: 'candyMachine' })], name: 'myProgramA', publicKey: '1111', }), [ programNode({ accounts: [accountNode({ name: 'candyMachine' })], name: 'myProgramB', publicKey: '2222', }), ], ); // When we update the name of that account in the first program. const result = visit( node, updateAccountsVisitor({ 'myProgramA.candyMachine': { name: 'newCandyMachine' }, }), ); // Then we expect the first account to have been renamed. assertIsNode(result, 'rootNode'); expect(result.program.accounts[0].name).toBe('newCandyMachine' as CamelCaseString); // But not the second account. expect(result.additionalPrograms[0].accounts[0].name).toBe('candyMachine' as CamelCaseString); }); test("it renames the fields of an account's data", () => { // Given the following account. const node = accountNode({ data: structTypeNode([structFieldTypeNode({ name: 'myData', type: numberTypeNode('u32') })]), name: 'myAccount', }); // When we rename its data fields. const result = visit( node, updateAccountsVisitor({ myAccount: { data: { myData: 'myNewData' }, }, }), ); // Then we expect the following tree changes. assertIsNode(result, 'accountNode'); const data = resolveNestedTypeNode(result.data); expect(data.fields[0].name).toBe('myNewData' as CamelCaseString); }); test('it updates the name of associated PDA nodes', () => { // Given the following program node with one account // and PDA accounts such that one of them is named the same. const node = programNode({ accounts: [accountNode({ name: 'myAccount' })], name: 'myProgram', pdas: [pdaNode({ name: 'myAccount', seeds: [] }), pdaNode({ name: 'myOtherAccount', seeds: [] })], publicKey: '1111', }); // When we update the name of that account. const result = visit( node, updateAccountsVisitor({ myAccount: { name: 'myNewAccount' }, }), ); // Then we expect the associated PDA node to have been renamed. assertIsNode(result, 'programNode'); expect(result.pdas[0].name).toBe('myNewAccount' as CamelCaseString); // But not the other PDA node. expect(result.pdas[1].name).toBe('myOtherAccount' as CamelCaseString); }); test('it creates a new PDA node when providing seeds to an account with no linked PDA', () => { // Given the following program node with one account. const node = rootNode( programNode({ accounts: [accountNode({ name: 'myAccount' })], name: 'myProgramA', pdas: [], publicKey: '1111', }), [programNode({ name: 'myProgramB', publicKey: '2222' })], ); // When we update the account with PDA seeds. const seeds = [constantPdaSeedNodeFromString('utf8', 'myAccount')]; const result = visit( node, updateAccountsVisitor({ myAccount: { seeds }, }), ); assertIsNode(result, 'rootNode'); // Then we expect a new PDA node to have been created on the program. expect(result.program.pdas.length).toBe(1); expect(result.additionalPrograms[0].pdas.length).toBe(0); expect(result.program.pdas[0]).toEqual(pdaNode({ name: 'myAccount', seeds })); // And the account now links to the new PDA node. expect(result.program.accounts[0].pda).toEqual(pdaLinkNode('myAccount')); }); test('it updates the PDA node when the updated account name matches an existing PDA node', () => { // Given an account node and a PDA node with the same name // such that the account is not linked to the PDA. const node = programNode({ accounts: [accountNode({ name: 'myAccount' })], name: 'myProgram', pdas: [pdaNode({ name: 'myAccount', seeds: [] })], publicKey: '1111', }); // When we update the account with PDA seeds. const seeds = [constantPdaSeedNodeFromString('utf8', 'myAccount')]; const result = visit( node, updateAccountsVisitor({ myAccount: { seeds }, }), ); assertIsNode(result, 'programNode'); // Then we expect the PDA node with the same name to have been updated. expect(result.pdas.length).toBe(1); expect(result.pdas[0]).toEqual(pdaNode({ name: 'myAccount', seeds })); // And the account now links to this PDA node. expect(result.accounts[0].pda).toEqual(pdaLinkNode('myAccount')); }); test('it updates the PDA node with the provided seeds when an account is linked to a PDA', () => { // Given an account node and a PDA node with a different name // such that the account is linked to the PDA. const node = programNode({ accounts: [accountNode({ name: 'myAccount', pda: pdaLinkNode('myPda') })], name: 'myProgram', pdas: [pdaNode({ name: 'myPda', seeds: [] })], publicKey: '1111', }); // When we update the account with PDA seeds. const seeds = [constantPdaSeedNodeFromString('utf8', 'myAccount')]; const result = visit( node, updateAccountsVisitor({ myAccount: { seeds }, }), ); assertIsNode(result, 'programNode'); // Then we expect the linked PDA node to have been updated. expect(result.pdas.length).toBe(1); expect(result.pdas[0]).toEqual(pdaNode({ name: 'myPda', seeds })); // And the account still links to the PDA node. expect(result.accounts[0].pda).toEqual(pdaLinkNode('myPda')); }); test('it creates a new PDA node when updating an account with seeds and a new linked PDA that does not exist', () => { // Given an account node with no linked PDA. const node = programNode({ accounts: [accountNode({ name: 'myAccount' })], name: 'myProgram', publicKey: '1111', }); // When we update the account with PDA seeds and a new linked PDA node. const seeds = [constantPdaSeedNodeFromString('utf8', 'myAccount')]; const result = visit( node, updateAccountsVisitor({ myAccount: { pda: pdaLinkNode('myPda'), seeds, }, }), ); assertIsNode(result, 'programNode'); // Then we expect the linked PDA node to have been created. expect(result.pdas.length).toBe(1); expect(result.pdas[0]).toEqual(pdaNode({ name: 'myPda', seeds })); // And the account now links to the PDA node. expect(result.accounts[0].pda).toEqual(pdaLinkNode('myPda')); }); test('it updates a PDA node when updating an account with seeds and a new linked PDA that exists', () => { // Given an account node with no linked PDA and an existing PDA node. const node = programNode({ accounts: [accountNode({ name: 'myAccount' })], name: 'myProgram', pdas: [pdaNode({ name: 'myPda', seeds: [] })], publicKey: '1111', }); // When we update the account with PDA seeds and a linked PDA node that points to the existing PDA. const seeds = [constantPdaSeedNodeFromString('utf8', 'myAccount')]; const result = visit( node, updateAccountsVisitor({ myAccount: { pda: pdaLinkNode('myPda'), seeds, }, }), ); assertIsNode(result, 'programNode'); // Then we expect the existing PDA node to have been updated. expect(result.pdas.length).toBe(1); expect(result.pdas[0]).toEqual(pdaNode({ name: 'myPda', seeds })); // And the account now links to this PDA node. expect(result.accounts[0].pda).toEqual(pdaLinkNode('myPda')); }); test('it can update the seeds and name of an account at the same time', () => { // Given an account node with no linked PDA. const node = programNode({ accounts: [accountNode({ name: 'myAccount' })], name: 'myProgram', publicKey: '1111', }); // When we update the name and seeds of the account. const seeds = [constantPdaSeedNodeFromString('utf8', 'myAccount')]; const result = visit( node, updateAccountsVisitor({ myAccount: { name: 'myNewAccount', seeds, }, }), ); assertIsNode(result, 'programNode'); // Then we expect the account name to have been updated. expect(result.accounts[0].name).toBe('myNewAccount' as CamelCaseString); // And a new PDA node to have been created with that new name and the provided seeds. expect(result.pdas.length).toBe(1); expect(result.pdas[0]).toEqual(pdaNode({ name: 'myNewAccount', seeds })); // And the account to now link to the PDA node. expect(result.accounts[0].pda).toEqual(pdaLinkNode('myNewAccount')); }); ================================================ FILE: packages/visitors/test/updateInstructionsVisitor.test.ts ================================================ import { ArgumentValueNode, argumentValueNode, assertIsNode, CamelCaseString, ConstantDiscriminatorNode, constantDiscriminatorNode, constantValueNode, instructionAccountNode, instructionArgumentNode, instructionByteDeltaNode, instructionNode, instructionRemainingAccountsNode, numberTypeNode, NumberValueNode, numberValueNode, programNode, rootNode, } from '@codama/nodes'; import { visit } from '@codama/visitors-core'; import { expect, test } from 'vitest'; import { updateInstructionsVisitor } from '../src'; test('it updates the name of an instruction', () => { // Given the following program node with one instruction. const node = programNode({ instructions: [instructionNode({ name: 'myInstruction' })], name: 'myProgram', publicKey: '1111', }); // When we update the name of that instruction. const result = visit( node, updateInstructionsVisitor({ myInstruction: { name: 'myNewInstruction' }, }), ); // Then we expect the following tree changes. assertIsNode(result, 'programNode'); expect(result.instructions[0].name).toBe('myNewInstruction' as CamelCaseString); }); test('it updates the name of an instruction within a specific program', () => { // Given two programs each with an instruction of the same name. const node = rootNode( programNode({ instructions: [instructionNode({ name: 'transfer' })], name: 'myProgramA', publicKey: '1111', }), [ programNode({ instructions: [instructionNode({ name: 'transfer' })], name: 'myProgramB', publicKey: '2222', }), ], ); // When we update the name of that instruction in the first program. const result = visit( node, updateInstructionsVisitor({ 'myProgramA.transfer': { name: 'newTransfer' }, }), ); // Then we expect the first instruction to have been renamed. assertIsNode(result, 'rootNode'); expect(result.program.instructions[0].name).toBe('newTransfer' as CamelCaseString); // But not the second instruction. expect(result.additionalPrograms[0].instructions[0].name).toBe('transfer' as CamelCaseString); }); test('it updates the name of an instruction account', () => { // Given the following instruction node with one account. const node = instructionNode({ accounts: [ instructionAccountNode({ isSigner: false, isWritable: true, name: 'myAccount', }), ], name: 'myInstruction', }); // When we update the name of that instruction account. const result = visit( node, updateInstructionsVisitor({ myInstruction: { accounts: { myAccount: { name: 'myNewAccount' }, }, }, }), ); // Then we expect the following tree changes. assertIsNode(result, 'instructionNode'); expect(result.accounts[0].name).toBe('myNewAccount' as CamelCaseString); }); test('it updates the name of an instruction argument', () => { // Given the following instruction node with one argument. const node = instructionNode({ arguments: [ instructionArgumentNode({ name: 'myArgument', type: numberTypeNode('u8'), }), ], name: 'myInstruction', }); // When we update the name of that instruction argument. const result = visit( node, updateInstructionsVisitor({ myInstruction: { arguments: { myArgument: { name: 'myNewArgument' }, }, }, }), ); // Then we expect the following tree changes. assertIsNode(result, 'instructionNode'); expect(result.arguments[0].name).toBe('myNewArgument' as CamelCaseString); }); test('it updates the default value of an instruction argument', () => { // Given the following instruction node with a argument that has no default value. const node = instructionNode({ arguments: [ instructionArgumentNode({ name: 'amount', type: numberTypeNode('u64'), }), ], name: 'transferTokens', }); // When we update the default value of that instruction argument. const result = visit( node, updateInstructionsVisitor({ transferTokens: { arguments: { amount: { defaultValue: numberValueNode(1) }, }, }, }), ); // Then we expect the following tree changes. assertIsNode(result, 'instructionNode'); expect(result.arguments[0].defaultValue).toEqual(numberValueNode(1)); expect(result.arguments[0].defaultValueStrategy).toBeUndefined(); }); test('it updates the default value strategy of an instruction argument', () => { // Given the following instruction node with two arguments that have no default values. const node = instructionNode({ arguments: [ instructionArgumentNode({ name: 'discriminator', type: numberTypeNode('u8'), }), instructionArgumentNode({ name: 'amount', type: numberTypeNode('u64'), }), ], name: 'transferTokens', }); // When we update the default value of these arguments using specific strategies. const result = visit( node, updateInstructionsVisitor({ transferTokens: { arguments: { amount: { defaultValue: numberValueNode(1), defaultValueStrategy: 'optional', }, discriminator: { defaultValue: numberValueNode(42), defaultValueStrategy: 'omitted', }, }, }, }), ); // Then we expect the following tree changes. assertIsNode(result, 'instructionNode'); expect(result.arguments[0].defaultValue).toEqual(numberValueNode(42)); expect(result.arguments[0].defaultValueStrategy).toBe('omitted'); expect(result.arguments[1].defaultValue).toEqual(numberValueNode(1)); expect(result.arguments[1].defaultValueStrategy).toBe('optional'); }); test('it updates the byteDeltas of an instruction', () => { // Given the following instruction node with no byteDeltas. const node = instructionNode({ name: 'myInstruction', }); // When we update the byteDeltas of that instruction. const result = visit( node, updateInstructionsVisitor({ myInstruction: { byteDeltas: [instructionByteDeltaNode(numberValueNode(100))], }, }), ); // Then we expect the following tree changes. assertIsNode(result, 'instructionNode'); expect(result.byteDeltas).toEqual([instructionByteDeltaNode(numberValueNode(100))]); }); test('it updates the discriminators of an instruction', () => { // Given the following instruction node with no discriminators. const node = instructionNode({ name: 'myInstruction', }); // When we update the discriminators of that instruction. const result = visit( node, updateInstructionsVisitor({ myInstruction: { discriminators: [ constantDiscriminatorNode(constantValueNode(numberTypeNode('u64'), numberValueNode(42))), ], }, }), ); // Then we expect the following tree changes. assertIsNode(result, 'instructionNode'); expect(result.discriminators![0].kind).toBe('constantDiscriminatorNode'); expect(((result.discriminators![0] as ConstantDiscriminatorNode).constant.value as NumberValueNode).number).toEqual( 42, ); }); test('it updates the remainingAccounts of an instruction', () => { // Given the following instruction node with no remaining accounts. const node = instructionNode({ name: 'myInstruction', }); // When we update the remaining accounts of that instruction. const result = visit( node, updateInstructionsVisitor({ myInstruction: { remainingAccounts: [instructionRemainingAccountsNode(argumentValueNode('abc'))], }, }), ); // Then we expect the following tree changes. assertIsNode(result, 'instructionNode'); expect(result.remainingAccounts![0].kind).toBe('instructionRemainingAccountsNode'); expect((result.remainingAccounts![0].value as ArgumentValueNode).name).toBe('abc'); }); ================================================ FILE: packages/visitors/tsconfig.declarations.json ================================================ { "compilerOptions": { "declaration": true, "declarationMap": true, "emitDeclarationOnly": true, "outDir": "./dist/types" }, "extends": "./tsconfig.json", "include": ["src/index.ts", "src/types"] } ================================================ FILE: packages/visitors/tsconfig.json ================================================ { "$schema": "https://json.schemastore.org/tsconfig", "compilerOptions": { "lib": [] }, "display": "@codama/visitors", "extends": "../../tsconfig.json", "include": ["src", "test"] } ================================================ FILE: packages/visitors/tsup.config.ts ================================================ import { defineConfig } from 'tsup'; import { getPackageBuildConfigs } from '../../tsup.config.base'; export default defineConfig(getPackageBuildConfigs()); ================================================ FILE: packages/visitors/vitest.config.mts ================================================ import { defineConfig } from 'vitest/config'; import { getVitestConfig } from '../../vitest.config.base.mjs'; export default defineConfig({ test: { projects: [getVitestConfig('browser'), getVitestConfig('node'), getVitestConfig('react-native')], }, }); ================================================ FILE: packages/visitors-core/.gitignore ================================================ dist/ ================================================ FILE: packages/visitors-core/.prettierignore ================================================ dist/ test/e2e/ test-ledger/ target/ CHANGELOG.md ================================================ FILE: packages/visitors-core/LICENSE ================================================ MIT License Copyright (c) 2025 Codama Copyright (c) 2024 Metaplex Foundation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: packages/visitors-core/README.md ================================================ # Codama ➤ Visitors ➤ Core [![npm][npm-image]][npm-url] [![npm-downloads][npm-downloads-image]][npm-url] [npm-downloads-image]: https://img.shields.io/npm/dm/@codama/visitors-core.svg?style=flat [npm-image]: https://img.shields.io/npm/v/@codama/visitors-core.svg?style=flat&label=%40codama%2Fvisitors-core [npm-url]: https://www.npmjs.com/package/@codama/visitors-core This package provides core interfaces and utilities for creating visitors for Codama IDLs. ## Installation ```sh pnpm install @codama/visitors-core ``` > [!NOTE] > This package is included in the [`@codama/visitors`](../visitors) package and in the main [`codama`](../library) library. Meaning, you already have access to its content if you are installing Codama in one of these ways. > > ```sh > pnpm install @codama/visitors > pnpm install codama > ``` ## Getting started with visitors ### The `Visitor` type The type `Visitor` is the core interface for defining Codama visitors. The type parameter `T` is used to determine the return type of the visitor. For instance, here's the definition of a visitor that goes through the nodes and returns a number. ```ts let myNumberVisitor: Visitor; ``` The `Visitor` type accepts a second type parameter which defines the scope of nodes accepted by the visitor. By default, the visitor accepts all nodes. However, you can restrict the visitor to a specific set of nodes by providing a union of node kinds. ```ts let myVisitorForProgramNodesOnly: Visitor; let myVisitorForTypeNodesOnly: Visitor; ``` The definition of the `Visitor` type is an object such that, for each supported node kind, a function that accepts a node of that kind and returns a value of type `T` is defined. The name of the function must be camel-cased, start with `visit` and finish with the name of the node kind without the `Node` suffix. For instance, the function for the `programNode` kind is named `visitProgram`. ### Writing your own visitor To write a custom visitor, you may simply define an object with the appropriate functions. For instance, here's a visitor that only visits `ProgramNodes` and returns the number of accounts in the program. ```ts const accountCounterVisitor: Visitor = { visitProgram: (node: ProgramNode) => node.accounts.length, }; ``` Note that it is recommended to return visitors from functions so we can easily reuse them and parameterize them. Additionally, this allows our code to be tree-shaken by the bundler. As we will see in this documentation, all provided visitors are returned from functions even if they don't take any parameter. Here's our previous example updated to accept a `multiplier` parameter. ```ts const accountCounterVisitor = (multiplier = 1): Visitor => ({ visitProgram: (node: ProgramNode) => node.accounts.length * multiplier, }); ``` In practice, writing a visitor manually can be cumbersome as a function must be provided for each supported node kind. Therefore, it is recommended to compose visitors from a set of core visitors provided by this package and extend them to suit your needs. We will see how to do this in the next sections. ### Visiting nodes Once we have a visitor, we can visit any node it supports by calling the `visit` function. This function accepts a node and a visitor of type `Visitor` and returns a type `T`. ```ts const counter: number = visit(programNode, accountCounterVisitor()); ``` The `visitOrElse` function can also be used to gracefully handle the case where the node is not supported by the visitor. In this case, a fallback logic — provided as a third argument — is used to compute the result. ```ts const counter: number = visit(stringTypeNode, accountCounterVisitor(), () => 0); ``` Also note that, if you are using [the `Codama` interface](../library/README#codama) — which is a simple wrapper around a `RootNode` — you may visit that root node using the provided helpers: ```ts // Runs the visitor and returns the result. const result: number = codama.accept(myNumberVisitor()); // Runs the visitor and updates the wrapped `RootNode` with the result. codama.update(myTransformerVisitor()); ``` ## Core visitors As mentioned in the previous section, creating visitors is much easier when we start from a set of core visitors and extend them to suit our needs. Therefore, let's start by exploring the core visitors provided by this package. ### Filtering node kinds Before we list each available core visitor, it is important to know that each of these functions optionally accepts a node kind or an array of node kinds **as a `keys` attribute in their `options`**. This allows us to restrict the visitor to a specific set of nodes and will return a `Visitor` instance where `U` is the union of the provided node kinds. Here are some examples: ```ts // This visitor only accepts `ProgramNodes`. const visitor: Visitor = voidVisitor({ keys: 'programNode' }); // This visitor accepts both `NumberTypeNodes` and `StringTypeNodes`. const visitor: Visitor = voidVisitor({ keys: ['numberTypeNode', 'stringTypeNode'], }); // This visitor accepts all type nodes. const visitor: Visitor = voidVisitor({ keys: TYPE_NODES }); // This visitor accepts all nodes. const visitor: Visitor = voidVisitor(); ``` In the following sections describing the core visitors, this exact pattern can be used to restrict the visitors to specific node kinds. We won't cover this for each visitor but know that you can achieve this via the `keys` option of each function. ### `voidVisitor` The `voidVisitor` traverses all the nodes and ends up returning `undefined`, regardless of the node kind. ```ts visit(node, voidVisitor()); // ^ undefined ``` Visiting a node with this visitor does nothing and causes no side effects. However, it can be a great starting point for creating new visitors by extending certain visiting functions of the `voidVisitor`. ### `staticVisitor` The `staticVisitor` accepts a function that is used for every node. The provided function is called with the node being visited. ```ts const visitor: Visitor = staticVisitor(node => `Visiting ${node.kind}`); const kind = visit(numberTypeNode('u32'), visitor); // ^ "Visiting numberTypeNode" ``` This visitor can be used to create simple visitors where each node shares a similar logic or to provide a starting point for more complex visitors. ### `identityVisitor` The `identityVisitor` traverses the nodes and returns a deep copy of the visited node. ```ts const node = visit(numberTypeNode('u32'), identityVisitor()); // ^ A different instance of numberTypeNode('u32') ``` Note that the returned visitor is of type `Visitor` meaning this visitor allows for nodes to be deleted — i.e. marked as `null`. The `identityVisitor` can resolve nested `null` references depending on the node kind. For instance, if a `tupleTypeNode` contains two items and the first one is `null` — after having visited its children — then, the `tupleTypeNode` will only contain the second item. It is also possible for a nested `null` reference to bubble up if it cannot be resolved. Here are some examples of this behaviour by overriding the `visitPublicKeyType` function to return `null`. ```ts const visitor = identityVisitor(); visitor.visitPublicKeyType = () => null; const node = visit(tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()]), visitor); // ^ tupleTypeNode([numberTypeNode('u32')]) const node = visit(definedTypeNode({ name: 'address', type: publicKeyTypeNode() }), visitor); // ^ null ``` Also note that, because the visitor is of type `Node | null`, it is technically possible to extend it such that a node of a different kind is returned. ```ts const visitor = identityVisitor(); visitor.visitPublicKeyType = () => fixedSizeTypeNode(stringTypeNode('base58'), 32); ``` ### `nonNullableIdentityVisitor` The `nonNullableIdentityVisitor` works the same way as the `identityVisitor` but it does not allow nodes to be deleted. That is, its return type must be a `Node` and not `Node | null`. ```ts const node = visit(numberTypeNode('u32'), nonNullableIdentityVisitor()); // ^ A different instance of numberTypeNode('u32') ``` ### `mergeVisitor` The `mergeVisitor` returns a `Visitor` by accepting two functions such that: - The first function is used on the leaves of the Codama IDL and returns a type `T`. - The second function is used to merge the values `T[]` of the children of a node and aggregate them into a type `T`. For instance, here is how we can use the `mergeVisitor` to create a nested string representation of node kinds. ```ts const visitor = mergeVisitor( (node): string => node.kind, (node, values: string[]): string => `${node.kind}(${values.join(',')})`, ); const result = visit(tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()]), visitor); // ^ "tupleTypeNode(numberTypeNode,publicKeyTypeNode)" ``` Here's another example, counting the number of traversed nodes. ```ts const visitor = mergeVisitor( () => 1, (, values) => values.reduce((a, b) => a + b, 1), ); const result = visit(tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()]), visitor); // ^ 3 ``` The `mergeVisitor` is a powerful starting point to create aggregating visitors. ## Composing visitors The following visitor functions accept an existing visitor and return a new visitor that extends or modifies the behaviour of the provided visitor. These primitives can be used to create complex visitors by composing simpler ones. ### `extendVisitor` The `extendVisitor` function accepts a base visitor and a set of function wrappers that are used to extend the behaviour of the base visitor. Each function wrapper is given the `node` being visited and an object composed of two elements: - `next`: A function that can be called to delegate to the base visitor — e.g. `next(node)`. - `self`: The visitor itself, allowing for recursive calls. To illustrate this, consider the following base visitor that counts the number of nodes. ```ts const baseVisitor = mergeVisitor( () => 1, (_, values) => values.reduce((a, b) => a + b, 1), ); ``` We can extend this visitor to increment the count by 10 when visiting a `PublicKeyTypeNode` like so: ```ts const visitor = extendVisitor(baseVisitor, { visitPublicKeyType: (node, { next }) => next(node) + 10, }); const result = visit(tupleTypeNode([publicKeyTypeNode(), numberTypeNode('u32')]), visitor); // ^ 13 ``` Notice how `next(node)` can be used to access the underlying visitor meaning we can extend both the input and the output of the base visitor. Another example is to make use of the `self` property to recursively call the extended visitor. For instance, the following code only visits the first item of tuple types. ```ts const visitor = extendVisitor(baseVisitor, { visitTupleType: (node, { self }) => visit(node.items[0], self) + 1, }); const result = visit(tupleTypeNode([tupleTypeNode([publicKeyTypeNode()]), numberTypeNode('u32')]), visitor); // ^ 3 ``` ### `interceptVisitor` The `interceptVisitor` allows us to wrap every visiting function of a provided visitor into a given function. This function has access to the node being visited and a `next` function that can be called to delegate to the base visitor. For instance, the following visitor intercepts a `voidVisitor` and captures events when visiting nodes. ```ts const events: string[] = []; const visitor = interceptVisitor(voidVisitor(), (node, next) => { events.push(`down:${node.kind}`); next(node); events.push(`up:${node.kind}`); }); visit(tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()]), visitor); // events === [ // 'down:tupleTypeNode', // 'down:numberTypeNode', // 'up:numberTypeNode', // 'down:publicKeyTypeNode', // 'up:publicKeyTypeNode', // 'up:tupleTypeNode', // ] ``` ### `interceptFirstVisitVisitor` The `interceptFirstVisitVisitor` works the same way as the `interceptVisitor` but only intercepts the first visit of a node. This means that the provided function is called when visiting the specific node provided but not when visiting its children. The parameters are the same as for the `interceptVisitor`. For instance, the following visitor intercepts a `voidVisitor` and captures events only during the first visit. ```ts const events: string[] = []; const visitor = interceptFirstVisitVisitor(voidVisitor(), (node, next) => { events.push(`down:${node.kind}`); next(node); events.push(`up:${node.kind}`); }); visit(tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()]), visitor); // events === [ // 'down:tupleTypeNode', // 'up:tupleTypeNode', // ] ``` ### `tapVisitor` The `tapVisitor` function allows us to tap into the visiting functions of a provided visitor without modifying its behaviour. This means the returned visitor will behave exactly like the base visitor except that the provided function will be called for the specified node kind. Note that the provided function must not return a value as it is only used for side effects. ```ts let numberOfNumberNodes = 0; const visitor = tapVisitor(voidVisitor(), 'numberTypeNode', node => { numberOfNumberNodes++; }); visit(tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()]), visitor); // numberOfNumberNodes === 1 ``` ### `mapVisitor` The `mapVisitor` function accepts a base visitor of type `Visitor` and a function of type `(value: T) => U`; and returns a new visitor of type `Visitor`. ```ts // Gets a nested string representation of node kinds. const baseVisitor = mergeVisitor( node => node.kind as string, (node, values) => `${node.kind}(${values.join(',')})`, ); // Counts the number of characters in the string representation. const visitor = mapVisitor(baseVisitor, (value: string): number => value.length); const result = visit(tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()]), visitor); // ^ 47 ``` ### `pipe` The `pipe` helper function allows us to compose visitors in a more readable way. It accepts a base visitor and a set of visitor functions that are used to extend the behaviour of the previous visitor at each step. ```ts const visitor = pipe( baseVisitor, v => extendVisitor(v /** ... */), v => interceptVisitor(v /** ... */), v => mapVisitor(v /** ... */), v => tapVisitor(v /** ... */), ); ``` For instance, here's an example using the `pipe` function to transform an `identityVisitor` into a visitor that: - Transforms all number types into `u64` numbers. - Logs the amount of items in tuple types. - Wraps the visited node in a `DefinedTypeNode` labelled "gift". ```ts const visitor = pipe( // Starts with the identity visitor. identityVisitor(), v => // Extends the visitor to make all number types u64. extendVisitor(v, { visitNumberType: node => numberTypeNode('u64'), }), v => // Log the amount of items in tuple types. tapVisitor(v, 'tupleTypeNode', node => { console.log(node.items.length); }), v => // Wrap the visited node in a `DefinedTypeNode` labelled "gift". interceptVisitor(v, node => (node, next) => { return definedTypeNode({ name: 'gift', type: next(node) }); }), ); ``` ### `singleNodeVisitor` The `singleNodeVisitor` function is a simple primitive that creates a `Visitor` that only visits a single node kind. It accepts a node kind and a function that is used to visit that node kind. Any other node kind will not be supported by the visitor. ```ts const visitor = singleNodeVisitor('tupleTypeNode', node => node.items.length); const result = visit(tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()]), visitor); // ^ 2 ``` Additionally, a `rootNodeVisitor` shortcut is provided to create a visitor that only visits `RootNodes`. This can be useful to design top-level visitors using custom logic. For instance, we can create a visitor that takes a `RootNode` and updates it through a series of other visitors before returning the updated `RootNode`. ```ts const visitor = rootNodeVisitor((root: RootNode) => { let newRoot = root; newRoot = visit(newRoot, visitorA); newRoot = visit(newRoot, visitorB); newRoot = visit(newRoot, visitorC); return newRoot; }); ``` ## Recording node paths ### `NodePath` The `NodePath` type defines an immutable array of `Nodes` that represents any path of nodes in the Codama IDL. It accepts an optional type parameter that tells us the type of the last node in the path. For instance `NodePath` represents a path of node ending with a `NumberTypeNode`. Additionally, there are several utility functions to use with `NodePath` instances: ```ts // An example of a node path. const path: NodePath = [rootNode, programNode, accountNode]; // Access the last node in the path. I.e. given NodePath, returns T. const lastNode: AccountNode = getLastNodeFromPath(path); // Access the first/last node of a specific kind in the path. const firstProgramNode: ProgramNode | undefined = findFirstNodeFromPath(path, 'programNode'); const lastProgramNode: ProgramNode | undefined = findLastNodeFromPath(path, 'programNode'); // Access the last program/instruction node in the path (sugar for `findLastNodeFromPath`). const programNode: ProgramNode | undefined = findProgramNodeFromPath(path); const instructionNode: InstructionNode | undefined = findInstructionNodeFromPath(path); // Get the subpath of a path from the beginning to the last node matching a specific kind. const subpath: NodePath = getNodePathUntilLastNode(path, 'programNode'); // ^ [rootNode, programNode] // Check that a path is not empty. if (isFilledNodePath(path as NodePath)) { path satisfies NodePath; } // Check that a path finishes with a node matching the provided kind or kinds. if (isNodePath(path as NodePath, ['AccountNode', 'InstructionNode'])) { path satisfies NodePath; } // Assert that a path finishes with a node matching the provided kind or kinds. assertIsNodePath(path as NodePath, ['AccountNode', 'InstructionNode']); path satisfies NodePath; // Display paths as strings or arrays of strings. nodePathToStringArray(path); // -> ['[rootNode]', '[programNode]token', '[accountNode]mint'] nodePathToString(path); // -> "[rootNode] > [programNode]token > [accountNode]mint" ``` ### `NodeStack` The `NodeStack` class is a utility that allows us to record the path of nodes that led to the node being currently visited. It is essentially a mutable version of `NodePath` that pushes and pops `Nodes` as we go down and up the tree of nodes. For instance, consider the following node: ```ts const node = definedTypeNode({ name: 'myType', type: tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()]), }); ``` In this example, the `numberTypeNode` can be reached using the following stack: ```ts const stack = new NodeStack() .push(node) // -> definedTypeNode. .push(node.type) // -> tupleTypeNode. .push(node.type.items[0]); // -> numberTypeNode. ``` Once you have access to a `NodeStack` instance, you may use the following methods: ```ts // Push a node to the stack. nodeStack.push(node); // Pop the last node out of the stack. const lastNode = nodeStack.pop(); // Peek at the last node in the stack. const lastNode = nodeStack.peek(); // Get all the nodes in the stack as an immutable `NodePath` array. const path: NodePath = nodeStack.getPath(); // Get a `NodePath` whilst asserting on the last node kind. const path: NodePath = nodeStack.getPath('accountNode'); // Check if the stack is empty. const isEmpty = nodeStack.isEmpty(); // Clone the stack. const clonedStack = nodeStack.clone(); ``` Additionally, it is possible to save and restore multiple node paths within a `NodeStack` by using the `pushPath` and `popPath` methods. This is for more advanced uses cases where you need to jump from one part of the tree, to a different part of the tree, and back — without loosing the context of the original path. An application of this is when we need to follow a node from a `LinkNode` (see ["Resolving link nodes"](#resolving-link-nodes) below for more details). ```ts // Save the current path and push a new path. stack.pushPath([rootNode, programNode, linkableNode]); // Pop the current path and restore the previous path. const previousPath = stack.popPath(); ``` ### `recordNodeStackVisitor` The `recordNodeStackVisitor` function gives us a convenient way to record the stack of each node currently being visited. It accepts a base visitor and an empty `NodeStack` instance that will automatically be pushed and popped as the visitor traverses the nodes. This means that we can inject the `NodeStack` instance into another extension of the visitor to access the stack whilst visiting the nodes. Note that the `recordNodeStackVisitor` **should be the last visitor** in the pipe to ensure that the stack is correctly recorded and that the current node visited is part of the stack. For instance, here's how we can log the `NodeStack` of any base visitor as we visit the nodes. ```ts const stack = new NodeStack(); const visitor = pipe( baseVisitor, v => interceptVisitor(v, (node, next) => { console.log(nodePathToString(stack.getPath())); return next(node); }), v => recordNodeStackVisitor(v, stack), ); ``` Also note that some core visitors such as the `bottomUpTransformerVisitor` or the `getByteSizeVisitor` use a `NodeStack` internally to keep track of the current path. If you use these visitor within another visitor, you may wish to provide your own `NodeStack` instance as an option so that the same `NodeStack` is used across all visitors throughout the traversal. ```ts const stack = new NodeStack(); const byteSizeVisitor = getByteSizeVisitor(..., { stack }); const visitor = pipe( voidVisitor(), v => tapVisitor(v, 'definedTypeNode', node => { const byteSize = visit(node, byteSizeVisitor); console.log(`The byte size of ${node.name} is ${byteSize}`); }), v => recordNodeStackVisitor(v, stack), ); ``` ## Selecting nodes When visiting a tree of nodes, it is often useful to be explicit about the paths we want to select. For instance, I may want to delete all accounts from a program node named "token". To that end, the `NodeSelector` type represents a node selection that can take two forms: - A `NodeSelectorFunction` of type `(path: NodePath) => boolean`. In this case, the provided function is used to determine if the last node in the provided `NodePath` should be selected. - A `NodeSelectorPath` of type `string`. In this case, the provided string uses a simple syntax to select nodes. The `NodeSelectorPath` syntax is as follows: - Plain text is used to match the name of a node, if any. For instance, `token` will match any node named "token". - Square brackets `[]` are used to match the kind of a node. For instance, `[programNode]` will match any `ProgramNode`. - Plain text and square brackets can be combined to match both the name and the kind of a node. For instance, `[programNode]token` will match any `ProgramNode` named "token". - Plain texts and/or square brackets can be chained using dots `.` to match several nodes in the current `NodeStack`. - Dot-separated paths must follow the provided order but do not need to be contiguous or exhaustive. This means that `a.b.c` will match a `NodeStack` that looks like `x.a.y.b.z.c` but not `b.a.c`. - The last item of a dot-separated path must match the last node of the `NodeStack`. For instance, `a.b` will not match `a.b.x`. - The wildcard `*` can be used at the end of the path to match any node within the matching path. For instance, `a.b.*` will match `a.b.x`. Here are some examples: ```ts '[accountNode]'; // Matches any `AccountNode`. 'mint'; // Matches any node named "mint". '[accountNode]mint'; // Matches any `AccountNode` named "mint". '[programNode]token.[accountNode]mint'; // Matches any `AccountNode` named "mint" within a `ProgramNode` named "token". '[programNode]token.*'; // Matches any node within a `ProgramNode` named "token" (excluding the program node itself). 'token.[structTypeNode].amount'; // Matches any node named "amount" within a `StructTypeNode` within any node named "token". ``` The `NodeSelector` type is used by various visitors such as the `bottomUpTransformerVisitor` or the `deleteNodesVisitor` to help us select the nodes we want to transform or delete. ## Transforming nodes This package offers several visitors to facilitate the transformation and/or deletion of nodes. These visitors are designed to be used in conjunction with the `NodeSelector` type to select the nodes we want to transform/delete. ### `bottomUpTransformerVisitor` The `bottomUpTransformerVisitor` traverses the nodes and intercepts them on the way back up. This means that when we reach a node, we have already visited all its children. This visitor accepts an array of `transformers` where each transformer is an object with the following properties: - `select`: A `NodeSelector` or an array of `NodeSelectors` used to select the nodes we want to transform. When multiple selectors are provided, they must all match for the node to be selected. - `transform`: A function that accepts the selected node and its `NodeStack`; and returns a new node or `null` to delete the node. Here are a few examples: ```ts const visitor = bottomUpTransformerVisitor([ { // Transform all numbers into u64 numbers. select: '[numberTypeNode]', transform: () => numberTypeNode('u64'), }, { // Delete all account nodes that start with "m". select: [ '[accountNode]', path => { const node = getLastNodeFromPath(path); return 'name' in node && node.name.startsWith('m'); }, ], transform: () => null, }, { // Prefix all fields inside a defined type with "super". select: '[definedTypeNode]metadata.[structFieldTypeNode]', transform: node => structFieldTypeNode({ ...node, name: `super${pascalCase(node.name)}` }), }, ]); ``` Additionally, `transformers` can be provided directly as functions. In this case, the function is used to transform all the nodes and further filtering may be needed inside the function. ```ts const visitor = bottomUpTransformerVisitor([ (node, stack) => { if (!isNode(node, numberTypeNode)) { return node; } const swappedEndian = node.endian === 'be' ? 'le' : 'be'; return numberTypeNode(node.format, swappedEndian); }, ]); ``` By default, this visitor will keep track of its own `NodeStack` but you may provide your own via the `stack` option in order to share the same `NodeStack` across multiple visitors. ### `topDownTransformerVisitor` The `topDownTransformerVisitor` works the same way as the `bottomUpTransformerVisitor` but intercepts the nodes on the way down. This means that when we reach a node, we have not yet visited its children. ```ts const visitor = topDownTransformerVisitor([ { // Half the amount of all accounts and instructions in programs. // The other half won't be visited on the way down. select: '[programNode]', transform: node => programNode({ ...node, accounts: node.accounts.slice(0, Math.floor(node.accounts.length / 2)), instructions: node.instructions.slice(0, Math.floor(node.instructions.length / 2)), }), }, ]); ``` Here as well, you may use the `stack` option to provide your own `NodeStack` instance. ### `deleteNodesVisitor` The `deleteNodesVisitor` accepts an array of `NodeSelectors` and deletes all the nodes that match any of the provided selectors. Therefore, it is equivalent to using a transformer visitor such that the `transform` function returns `null` for the selected nodes. ```ts // Deletes all account nodes named "mint" and all number type nodes. const visitor = deleteNodesVisitor(['[accountNode]mint', '[numberTypeNode]']); ``` Here as well, you may use the `stack` option to provide your own `NodeStack` instance. ## String representations This package also offers visitors that help render nodes as strings. These visitors can be useful for debugging purposes as well as getting a unique hash string representation of a node. ### `getDebugStringVisitor` The `getDebugStringVisitor` provides a string representation of the nodes that can be used for debugging purposes. By default, it inlines the content of the nodes and does not include any indentation. ```ts const visitor = getDebugStringVisitor(); const result = visit(tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()]), visitor); // ^ "tupleTypeNode(numberTypeNode[u32], publicKeyTypeNode)" ``` However, you can provide the `indent` option to get a more readable string representation. ```ts const visitor = getDebugStringVisitor({ indent: true }); const result = visit(tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()]), visitor); // tupleTypeNode // | numberTypeNode [u32] // | publicKeyTypeNode ``` Note that this string does not always include every piece of information a node has to offer. Therefore, it cannot be used as a unique identifier for the content of a node. For that purpose, see the `getUniqueHashStringVisitor` below. ### `getUniqueHashStringVisitor` The `getUniqueHashStringVisitor` provides a unique string representation of the node that can be used to get a unique hash for that node. In other words, if two different nodes have the exact same content, they will output the same string. ```ts const visitor = getUniqueHashStringVisitor(); const result = visit(tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()]), visitor); // ^ '{"items":[{"endian":"le","format":"u32","kind":"numberTypeNode"},{"kind":"publicKeyTypeNode"}],"kind":"tupleTypeNode"}' ``` ### `consoleLogVisitor` The `consoleLogVisitor` accepts any `Visitor` and transforms it into a `Visitor` such that the provided `string` is logged to the console. ```ts // Outputs the indented debug string to the console. const visitor = consoleLogVisitor(getDebugStringVisitor({ indent: true })); ``` ## Resolving link nodes ### `LinkableDictionary` The `LinkableDictionary` type is a utility that allows us to store and access linkable nodes — such as `ProgramNodes`, `AccountNodes` or `PdaNodes` — from their respective [link nodes](../nodes/linkNodes/README.md). It offers the following API: ```ts const linkables = new LinkableDictionary(); // Record linkable nodes via their full path. linkables.recordPath([rootNode, programNode, accountNode]); // Get a linkable node using the full path of a link node, or return undefined if it is not found. const programNode: ProgramNode | undefined = linkables.get([...somePath, programLinkNode]); // Get a linkable node using the full path of a link node, or throw an error if it is not found. const programNode: ProgramNode = linkables.getOrThrow([...somePath, programLinkNode]); // Get the path of a linkable node using the full path of a link node, or return undefined if it is not found. const accountPath: NodePath | undefined = linkables.getPath([...somePath, accountLinkNode]); // Get the path of a linkable node using the full path of a link node, or throw an error if it is not found. const accountPath: NodePath = linkables.getPathOrThrow([...somePath, accountLinkNode]); ``` Note that: - The path of the recorded node must be provided when recording a linkable node. - The path of the link node must be provided when getting a linkable node (or its path) from it. This API may be used with the `recordLinkablesOnFirstVisitVisitor` to record the linkable nodes before the first node visit; as well as the `recordNodeStackVisitor` to keep track of the current node path when accessing the linkable nodes. ### `getRecordLinkablesVisitor` This visitor accepts a `LinkableDictionary` instance and records all linkable nodes it encounters when visiting the nodes. ```ts const linkables = new LinkableDictionary(); visit(rootNode, getRecordLinkablesVisitor(linkables)); // Now, all linkable nodes are recorded in the `linkables` dictionary. ``` ### `recordLinkablesOnFirstVisitVisitor` This visitor is a utility that combines `interceptFirstVisitVisitor` and `getRecordLinkablesVisitor` to record all linkable nodes before the first visit of any node. It accepts a base visitor and a `LinkableDictionary` instance; and returns a new visitor that records all linkable nodes it encounters before the very first visit of the provided base visitor. This means that we can inject the `LinkableDictionary` instance into other extensions of the base visitor to resolve any link node we encounter. Note that the `recordLinkablesOnFirstVisitVisitor` **should be the last visitor** in the pipe to ensure that all linkable nodes are recorded before being used. Here's an example that records a `LinkableDictionary` and uses it to log the amount of seeds in each linked PDA node. ```ts const linkables = new LinkableDictionary(); const stack = new NodeStack(); const visitor = pipe( baseVisitor, v => tapVisitor(v, 'pdaLinkNode', node => { const pdaNode = linkables.getOrThrow(stack.getPath(node.kind)); console.log(`${pdaNode.seeds.length} seeds`); }), v => recordNodeStackVisitor(v, stack), v => recordLinkablesOnFirstVisitVisitor(v, linkables), ); ``` ## Other useful visitors This package provides a few other visitors that may help build more complex visitors. ### `getByteSizeVisitor` The `getByteSizeVisitor` calculates the byte size of a given `TypeNode`. It returns a `number` if the byte size is fixed or `null` if it is variable. It requires a `LinkableDictionary` instance to resolve any link nodes it encounters. ```ts const visitor = getByteSizeVisitor(linkables); const size = visit(tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()]), visitor); // ^ 36 (4 bytes for the u32 number and 32 bytes for the public key) ``` By default, this visitor will keep track of its own `NodeStack` but you may provide your own via the `stack` option in order to share the same `NodeStack` across multiple visitors. ### `getResolvedInstructionInputsVisitor` The `getResolvedInstructionInputsVisitor` visits `InstructionNodes` only and returns an array of instruction accounts and arguments in the order they should be rendered for their default values to be resolved. For instance, say we have an instruction with two accounts and one argument such that `argumentA` defaults to `accountB` and `accountA` is a PDA that uses `argumentA` as a seed. Therefore, the visitor will return an array in the order `[accountB, argumentA, accountA]`. This is mostly useful when rendering client code for instructions. ### `removeDocsVisitor` The `removeDocsVisitor` goes through all nodes that have a `docs` property and clears its content. ```ts const node = definedTypeNode({ name: 'authority', type: publicKeyTypeNode(), docs: ['The authority of the account'], }); const updatedNode = visit(node, removeDocsVisitor()); // ^ definedTypeNode({ name: 'authority', type: publicKeyTypeNode() }) ``` This is used internally by the `getUniqueHashStringVisitor` to get a unique identifier for a node regardless of its documentation. ================================================ FILE: packages/visitors-core/package.json ================================================ { "name": "@codama/visitors-core", "version": "1.6.0", "description": "Core visitors for the Codama framework", "exports": { "types": "./dist/types/index.d.ts", "react-native": "./dist/index.react-native.mjs", "browser": { "import": "./dist/index.browser.mjs", "require": "./dist/index.browser.cjs" }, "node": { "import": "./dist/index.node.mjs", "require": "./dist/index.node.cjs" } }, "browser": { "./dist/index.node.cjs": "./dist/index.browser.cjs", "./dist/index.node.mjs": "./dist/index.browser.mjs" }, "main": "./dist/index.node.cjs", "module": "./dist/index.node.mjs", "react-native": "./dist/index.react-native.mjs", "types": "./dist/types/index.d.ts", "type": "commonjs", "files": [ "./dist/types", "./dist/index.*" ], "sideEffects": false, "keywords": [ "solana", "framework", "standard", "visitors" ], "scripts": { "build": "rimraf dist && tsup && tsc -p ./tsconfig.declarations.json", "dev": "vitest --project node", "lint": "eslint . && prettier --check .", "lint:fix": "eslint --fix . && prettier --write .", "test": "pnpm test:types && pnpm test:treeshakability && pnpm test:unit", "test:treeshakability": "for file in dist/index.*.mjs; do agadoo $file; done", "test:types": "tsc --noEmit", "test:unit": "vitest run" }, "dependencies": { "@codama/errors": "workspace:*", "@codama/nodes": "workspace:*", "json-stable-stringify": "^1.3.0" }, "devDependencies": { "@types/json-stable-stringify": "^1.2.0" }, "license": "MIT", "repository": { "type": "git", "url": "https://github.com/codama-idl/codama" }, "bugs": { "url": "http://github.com/codama-idl/codama/issues" }, "browserslist": [ "supports bigint and not dead", "maintained node versions" ] } ================================================ FILE: packages/visitors-core/src/LinkableDictionary.ts ================================================ import { CODAMA_ERROR__LINKED_NODE_NOT_FOUND, CodamaError } from '@codama/errors'; import { AccountNode, CamelCaseString, DefinedTypeNode, InstructionAccountNode, InstructionArgumentNode, InstructionNode, isNode, LinkNode, PdaNode, ProgramNode, } from '@codama/nodes'; import { findInstructionNodeFromPath, findProgramNodeFromPath, getLastNodeFromPath, getNodePathUntilLastNode, isNodePath, NodePath, } from './NodePath'; export type LinkableNode = | AccountNode | DefinedTypeNode | InstructionAccountNode | InstructionArgumentNode | InstructionNode | PdaNode | ProgramNode; export const LINKABLE_NODES: LinkableNode['kind'][] = [ 'accountNode', 'definedTypeNode', 'instructionAccountNode', 'instructionArgumentNode', 'instructionNode', 'pdaNode', 'programNode', ]; export type GetLinkableFromLinkNode = { accountLinkNode: AccountNode; definedTypeLinkNode: DefinedTypeNode; instructionAccountLinkNode: InstructionAccountNode; instructionArgumentLinkNode: InstructionArgumentNode; instructionLinkNode: InstructionNode; pdaLinkNode: PdaNode; programLinkNode: ProgramNode; }[TLinkNode['kind']]; type ProgramDictionary = { accounts: Map>; definedTypes: Map>; instructions: Map; pdas: Map>; program: NodePath; }; type InstructionDictionary = { accounts: Map>; arguments: Map>; instruction: NodePath; }; export class LinkableDictionary { readonly programs: Map = new Map(); recordPath(linkablePath: NodePath): this { const linkableNode = getLastNodeFromPath(linkablePath); const programDictionary = this.getOrCreateProgramDictionary(linkablePath); if (!programDictionary) return this; // Do not record nodes that are outside of a program. const instructionDictionary = this.getOrCreateInstructionDictionary(programDictionary, linkablePath); if (isNodePath(linkablePath, 'accountNode')) { programDictionary.accounts.set(linkableNode.name, linkablePath); } else if (isNodePath(linkablePath, 'definedTypeNode')) { programDictionary.definedTypes.set(linkableNode.name, linkablePath); } else if (isNodePath(linkablePath, 'pdaNode')) { programDictionary.pdas.set(linkableNode.name, linkablePath); } else if (instructionDictionary && isNodePath(linkablePath, 'instructionAccountNode')) { instructionDictionary.accounts.set(linkableNode.name, linkablePath); } else if (instructionDictionary && isNodePath(linkablePath, 'instructionArgumentNode')) { instructionDictionary.arguments.set(linkableNode.name, linkablePath); } return this; } getPathOrThrow( linkPath: NodePath, ): NodePath> { const linkablePath = this.getPath(linkPath); if (!linkablePath) { const linkNode = getLastNodeFromPath(linkPath); throw new CodamaError(CODAMA_ERROR__LINKED_NODE_NOT_FOUND, { kind: linkNode.kind, linkNode, name: linkNode.name, path: linkPath, }); } return linkablePath; } getPath( linkPath: NodePath, ): NodePath> | undefined { const linkNode = getLastNodeFromPath(linkPath); const programDictionary = this.getProgramDictionary(linkPath); if (!programDictionary) return undefined; const instructionDictionary = this.getInstructionDictionary(programDictionary, linkPath); type LinkablePath = NodePath> | undefined; if (isNode(linkNode, 'accountLinkNode')) { return programDictionary.accounts.get(linkNode.name) as LinkablePath; } else if (isNode(linkNode, 'definedTypeLinkNode')) { return programDictionary.definedTypes.get(linkNode.name) as LinkablePath; } else if (isNode(linkNode, 'instructionAccountLinkNode')) { return instructionDictionary?.accounts.get(linkNode.name) as LinkablePath; } else if (isNode(linkNode, 'instructionArgumentLinkNode')) { return instructionDictionary?.arguments.get(linkNode.name) as LinkablePath; } else if (isNode(linkNode, 'instructionLinkNode')) { return instructionDictionary?.instruction as LinkablePath; } else if (isNode(linkNode, 'pdaLinkNode')) { return programDictionary.pdas.get(linkNode.name) as LinkablePath; } else if (isNode(linkNode, 'programLinkNode')) { return programDictionary.program as LinkablePath; } return undefined; } getOrThrow(linkPath: NodePath): GetLinkableFromLinkNode { return getLastNodeFromPath(this.getPathOrThrow(linkPath)); } get(linkPath: NodePath): GetLinkableFromLinkNode | undefined { const path = this.getPath(linkPath); return path ? getLastNodeFromPath(path) : undefined; } has(linkPath: NodePath): boolean { const linkNode = getLastNodeFromPath(linkPath); const programDictionary = this.getProgramDictionary(linkPath); if (!programDictionary) return false; const instructionDictionary = this.getInstructionDictionary(programDictionary, linkPath); if (isNode(linkNode, 'accountLinkNode')) { return programDictionary.accounts.has(linkNode.name); } else if (isNode(linkNode, 'definedTypeLinkNode')) { return programDictionary.definedTypes.has(linkNode.name); } else if (isNode(linkNode, 'instructionAccountLinkNode')) { return !!instructionDictionary && instructionDictionary.accounts.has(linkNode.name); } else if (isNode(linkNode, 'instructionArgumentLinkNode')) { return !!instructionDictionary && instructionDictionary.arguments.has(linkNode.name); } else if (isNode(linkNode, 'instructionLinkNode')) { return programDictionary.instructions.has(linkNode.name); } else if (isNode(linkNode, 'pdaLinkNode')) { return programDictionary.pdas.has(linkNode.name); } else if (isNode(linkNode, 'programLinkNode')) { return true; } return false; } private getOrCreateProgramDictionary(linkablePath: NodePath): ProgramDictionary | undefined { const linkableNode = getLastNodeFromPath(linkablePath); const programNode = isNode(linkableNode, 'programNode') ? linkableNode : findProgramNodeFromPath(linkablePath); if (!programNode) return undefined; let programDictionary = this.programs.get(programNode.name); if (!programDictionary) { programDictionary = { accounts: new Map(), definedTypes: new Map(), instructions: new Map(), pdas: new Map(), program: getNodePathUntilLastNode(linkablePath, 'programNode')!, }; this.programs.set(programNode.name, programDictionary); } return programDictionary; } private getOrCreateInstructionDictionary( programDictionary: ProgramDictionary, linkablePath: NodePath, ): InstructionDictionary | undefined { const linkableNode = getLastNodeFromPath(linkablePath); const instructionNode = isNode(linkableNode, 'instructionNode') ? linkableNode : findInstructionNodeFromPath(linkablePath); if (!instructionNode) return undefined; let instructionDictionary = programDictionary.instructions.get(instructionNode.name); if (!instructionDictionary) { instructionDictionary = { accounts: new Map(), arguments: new Map(), instruction: getNodePathUntilLastNode(linkablePath, 'instructionNode')!, }; programDictionary.instructions.set(instructionNode.name, instructionDictionary); } return instructionDictionary; } private getProgramDictionary(linkPath: NodePath): ProgramDictionary | undefined { const linkNode = getLastNodeFromPath(linkPath); let programName: CamelCaseString | undefined = undefined; if (isNode(linkNode, 'programLinkNode')) { programName = linkNode.name; } else if ('program' in linkNode) { programName = linkNode.program?.name; } else if ('instruction' in linkNode) { programName = linkNode.instruction?.program?.name; } programName = programName ?? findProgramNodeFromPath(linkPath)?.name; return programName ? this.programs.get(programName) : undefined; } private getInstructionDictionary( programDictionary: ProgramDictionary, linkPath: NodePath, ): InstructionDictionary | undefined { const linkNode = getLastNodeFromPath(linkPath); let instructionName: CamelCaseString | undefined = undefined; if (isNode(linkNode, 'instructionLinkNode')) { instructionName = linkNode.name; } else if ('instruction' in linkNode) { instructionName = linkNode.instruction?.name; } instructionName = instructionName ?? findInstructionNodeFromPath(linkPath)?.name; return instructionName ? programDictionary.instructions.get(instructionName) : undefined; } } ================================================ FILE: packages/visitors-core/src/NodePath.ts ================================================ import { assertIsNode, GetNodeFromKind, InstructionNode, isNode, Node, NodeKind, ProgramNode } from '@codama/nodes'; export type NodePath = TNode extends undefined ? readonly Node[] : readonly [...(readonly Node[]), TNode]; export function getLastNodeFromPath(path: NodePath): TNode { return path[path.length - 1] as TNode; } export function findFirstNodeFromPath( path: NodePath, kind: TKind | TKind[], ): GetNodeFromKind | undefined { return path.find(node => isNode(node, kind)); } export function findLastNodeFromPath( path: NodePath, kind: TKind | TKind[], ): GetNodeFromKind | undefined { for (let index = path.length - 1; index >= 0; index--) { const node = path[index]; if (isNode(node, kind)) return node; } return undefined; } export function findProgramNodeFromPath(path: NodePath): ProgramNode | undefined { return findLastNodeFromPath(path, 'programNode'); } export function findInstructionNodeFromPath(path: NodePath): InstructionNode | undefined { return findLastNodeFromPath(path, 'instructionNode'); } export function getNodePathUntilLastNode( path: NodePath, kind: TKind | TKind[], ): NodePath> | undefined { const lastIndex = (() => { for (let index = path.length - 1; index >= 0; index--) { const node = path[index]; if (isNode(node, kind)) return index; } return -1; })(); if (lastIndex === -1) return undefined; return path.slice(0, lastIndex + 1) as unknown as NodePath>; } export function isFilledNodePath(path: NodePath | null | undefined): path is NodePath { return !!path && path.length > 0; } export function isNodePath( path: NodePath | null | undefined, kind: TKind | TKind[], ): path is NodePath> { return isNode(isFilledNodePath(path) ? getLastNodeFromPath(path) : null, kind); } export function assertIsNodePath( path: NodePath | null | undefined, kind: TKind | TKind[], ): asserts path is NodePath> { assertIsNode(isFilledNodePath(path) ? getLastNodeFromPath(path) : null, kind); } export function nodePathToStringArray(path: NodePath): string[] { return path.map((node): string => { return 'name' in node ? `[${node.kind}]${node.name}` : `[${node.kind}]`; }); } export function nodePathToString(path: NodePath): string { return nodePathToStringArray(path).join(' > '); } ================================================ FILE: packages/visitors-core/src/NodeSelector.ts ================================================ import { camelCase, CamelCaseString, Node } from '@codama/nodes'; import { NodePath } from './NodePath'; export type NodeSelector = NodeSelectorFunction | NodeSelectorPath; /** * A string that can be used to select a node in a Codama tree. * - `*` matches any node. * - `someText` matches the name of a node, if any. * - `[someNode]` matches a node of the given kind. * - `[someNode|someOtherNode]` matches a node with any of the given kind. * - `[someNode]someText` matches both the kind and the name of a node. * - `a.b.c` matches a node `c` such that its ancestors contains `a` and `b` in order (but not necessarily subsequent). */ export type NodeSelectorPath = string; export type NodeSelectorFunction = (path: NodePath) => boolean; export const getNodeSelectorFunction = (selector: NodeSelector): NodeSelectorFunction => { if (typeof selector === 'function') return selector; const checkNode = (node: Node, nodeSelector: string): boolean => { if (nodeSelector === '*') return true; const matches = nodeSelector.match(/^(?:\[([^\]]+)\])?(.*)?$/); if (!matches) return false; const [, kinds, name] = matches; // Check kinds. const kindArray = kinds ? kinds.split('|').map(camelCase) : []; if (kindArray.length > 0 && !kindArray.includes(node.kind as CamelCaseString)) { return false; } // Check names. if (name && (!('name' in node) || camelCase(name) !== node.name)) { return false; } return true; }; const checkPath = (path: Node[], nodeSelectors: string[]): boolean => { if (nodeSelectors.length === 0) return true; if (path.length === 0) return false; const lastNode = path.pop() as Node; const lastNodeSelector = nodeSelectors.pop() as string; return checkNode(lastNode, lastNodeSelector) ? checkPath(path, nodeSelectors) : checkPath(path, [...nodeSelectors, lastNodeSelector]); }; const checkInitialPath = (path: Node[], nodeSelectors: string[]): boolean => { if (nodeSelectors.length === 0 || path.length === 0) return false; const lastNode = path.pop() as Node; const lastNodeSelector = nodeSelectors.pop() as string; return checkNode(lastNode, lastNodeSelector) && checkPath(path, nodeSelectors); }; const nodeSelectors = selector.split('.'); return path => checkInitialPath([...path], [...nodeSelectors]); }; export const getConjunctiveNodeSelectorFunction = (selector: NodeSelector | NodeSelector[]): NodeSelectorFunction => { const selectors = Array.isArray(selector) ? selector : [selector]; const selectorFunctions = selectors.map(getNodeSelectorFunction); return path => selectorFunctions.every(fn => fn(path)); }; ================================================ FILE: packages/visitors-core/src/NodeStack.ts ================================================ import { CODAMA_ERROR__VISITORS__CANNOT_REMOVE_LAST_PATH_IN_NODE_STACK, CodamaError } from '@codama/errors'; import { GetNodeFromKind, Node, NodeKind } from '@codama/nodes'; import { assertIsNodePath, NodePath, nodePathToString } from './NodePath'; type MutableNodePath = Node[]; export class NodeStack { /** * Contains all the node paths saved during the traversal. * * - The very last path is the current path which is being * used during the traversal. * - The other paths can be used to save and restore the * current path when jumping to different parts of the tree. * * There must at least be one path in the stack at all times. */ private readonly stack: [...MutableNodePath[], MutableNodePath]; constructor(...stack: readonly [...(readonly NodePath[]), NodePath] | readonly []) { this.stack = stack.length === 0 ? [[]] : ([...stack.map(nodes => [...nodes])] as [...MutableNodePath[], MutableNodePath]); } private get currentPath(): MutableNodePath { return this.stack[this.stack.length - 1]; } public push(node: Node): void { this.currentPath.push(node); } public pop(): Node | undefined { return this.currentPath.pop(); } public peek(): Node | undefined { return this.isEmpty() ? undefined : this.currentPath[this.currentPath.length - 1]; } public pushPath(newPath: NodePath = []): void { this.stack.push([...newPath]); } public popPath(): NodePath { if (this.stack.length <= 1) { throw new CodamaError(CODAMA_ERROR__VISITORS__CANNOT_REMOVE_LAST_PATH_IN_NODE_STACK, { path: [...this.stack[this.stack.length - 1]], }); } return [...this.stack.pop()!]; } public getPath(): NodePath; public getPath(kind: TKind | TKind[]): NodePath>; public getPath(kind?: TKind | TKind[]): NodePath { const path = [...this.currentPath]; if (kind) { assertIsNodePath(path, kind); } return path; } public isEmpty(): boolean { return this.currentPath.length === 0; } public clone(): NodeStack { return new NodeStack(...this.stack); } public toString(): string { return nodePathToString(this.getPath()); } } ================================================ FILE: packages/visitors-core/src/bottomUpTransformerVisitor.ts ================================================ import { Node, NodeKind, REGISTERED_NODE_KINDS } from '@codama/nodes'; import { identityVisitor } from './identityVisitor'; import { interceptVisitor } from './interceptVisitor'; import { getConjunctiveNodeSelectorFunction, NodeSelector } from './NodeSelector'; import { NodeStack } from './NodeStack'; import { pipe } from './pipe'; import { recordNodeStackVisitor } from './recordNodeStackVisitor'; import { Visitor } from './visitor'; export type BottomUpNodeTransformer = (node: Node, stack: NodeStack) => Node | null; export type BottomUpNodeTransformerWithSelector = { select: NodeSelector | NodeSelector[]; transform: BottomUpNodeTransformer; }; export function bottomUpTransformerVisitor( transformers: (BottomUpNodeTransformer | BottomUpNodeTransformerWithSelector)[], options: { keys?: TNodeKind[]; stack?: NodeStack } = {}, ): Visitor { const transformerFunctions = transformers.map((transformer): BottomUpNodeTransformer => { if (typeof transformer === 'function') return transformer; return (node, stack) => getConjunctiveNodeSelectorFunction(transformer.select)(stack.getPath(REGISTERED_NODE_KINDS)) ? transformer.transform(node, stack) : node; }); const stack = options.stack ?? new NodeStack(); return pipe( identityVisitor(options), v => interceptVisitor(v, (node, next) => { return transformerFunctions.reduce( (acc, transformer) => (acc === null ? null : transformer(acc, stack)), next(node), ); }), v => recordNodeStackVisitor(v, stack), ); } ================================================ FILE: packages/visitors-core/src/consoleLogVisitor.ts ================================================ import { NodeKind } from '@codama/nodes'; import { mapVisitor } from './mapVisitor'; import { Visitor } from './visitor'; export function consoleLogVisitor( visitor: Visitor, ): Visitor { return mapVisitor(visitor, value => console.log(value)); } ================================================ FILE: packages/visitors-core/src/deleteNodesVisitor.ts ================================================ import { NodeKind } from '@codama/nodes'; import { NodeSelector } from './NodeSelector'; import { TopDownNodeTransformerWithSelector, topDownTransformerVisitor } from './topDownTransformerVisitor'; export function deleteNodesVisitor( selectors: NodeSelector[], options?: Parameters>[1], ) { return topDownTransformerVisitor( selectors.map( (selector): TopDownNodeTransformerWithSelector => ({ select: selector, transform: () => null, }), ), options, ); } ================================================ FILE: packages/visitors-core/src/extendVisitor.ts ================================================ import { CODAMA_ERROR__VISITORS__CANNOT_EXTEND_MISSING_VISIT_FUNCTION, CodamaError } from '@codama/errors'; import { GetNodeFromKind, Node, NodeKind, REGISTERED_NODE_KINDS } from '@codama/nodes'; import { getVisitFunctionName, GetVisitorFunctionName, Visitor } from './visitor'; // eslint-disable-next-line @typescript-eslint/no-explicit-any type DontInfer = T extends any ? T : never; export type VisitorOverrideFunction = ( node: TNode, scope: { next: (node: TNode) => TReturn; self: Visitor; }, ) => TReturn; export type VisitorOverrides = { [K in TNodeKind as GetVisitorFunctionName]?: VisitorOverrideFunction>; }; export function extendVisitor( visitor: Visitor, overrides: DontInfer>, ): Visitor { const registeredVisitFunctions = REGISTERED_NODE_KINDS.map(getVisitFunctionName); const overriddenFunctions = Object.fromEntries( Object.keys(overrides).flatMap(key => { if (!(registeredVisitFunctions as string[]).includes(key)) { return []; } const castedKey = key as GetVisitorFunctionName; if (!visitor[castedKey]) { throw new CodamaError(CODAMA_ERROR__VISITORS__CANNOT_EXTEND_MISSING_VISIT_FUNCTION, { visitFunction: castedKey, }); } return [ [ castedKey, function extendedVisitNode(this: Visitor, node: TNode) { const extendedFunction = overrides[castedKey] as VisitorOverrideFunction< TReturn, TNodeKind, TNode >; const nextFunction = visitor[castedKey] as unknown as (node: TNode) => TReturn; return extendedFunction.bind(this)(node, { next: nextFunction.bind(this), self: this, }); }, ], ]; }), ) as Partial>; return { ...visitor, ...overriddenFunctions, }; } ================================================ FILE: packages/visitors-core/src/getByteSizeVisitor.ts ================================================ import { CountNode, isNode, isScalarEnum, REGISTERED_TYPE_NODE_KINDS, RegisteredTypeNode } from '@codama/nodes'; import { extendVisitor } from './extendVisitor'; import { LinkableDictionary } from './LinkableDictionary'; import { mergeVisitor } from './mergeVisitor'; import { getLastNodeFromPath } from './NodePath'; import { NodeStack } from './NodeStack'; import { pipe } from './pipe'; import { recordNodeStackVisitor } from './recordNodeStackVisitor'; import { visit, Visitor } from './visitor'; export type ByteSizeVisitorKeys = | RegisteredTypeNode['kind'] | 'accountNode' | 'constantValueNode' | 'definedTypeLinkNode' | 'definedTypeNode' | 'instructionArgumentNode' | 'instructionNode'; export function getByteSizeVisitor( linkables: LinkableDictionary, options: { stack?: NodeStack } = {}, ): Visitor { const stack = options.stack ?? new NodeStack(); const visitedDefinedTypes = new Map(); const definedTypeStack: string[] = []; const sumSizes = (values: (number | null)[]): number | null => values.reduce((all, one) => (all === null || one === null ? null : all + one), 0 as number | null); const baseVisitor = mergeVisitor( () => null as number | null, (_, values) => sumSizes(values), { keys: [ ...REGISTERED_TYPE_NODE_KINDS, 'accountNode', 'constantValueNode', 'definedTypeLinkNode', 'definedTypeNode', 'instructionArgumentNode', 'instructionNode', ], }, ); return pipe( baseVisitor, v => extendVisitor(v, { visitAccount(node, { self }) { return visit(node.data, self); }, visitArrayType(node, { self }) { return getArrayLikeSize(node.count, visit(node.item, self), self); }, visitConstantValue(node, { self }) { const typeSize = visit(node.type, self); if (typeSize !== null) return typeSize; if (isNode(node.value, 'bytesValueNode') && node.value.encoding === 'base16') { return Math.ceil(node.value.data.length / 2); } if ( isNode(node.type, 'stringTypeNode') && node.type.encoding === 'base16' && isNode(node.value, 'stringValueNode') ) { return Math.ceil(node.value.string.length / 2); } // Technically, we could still identify other fixed-size constants // but we'd need to import @solana/codecs to compute them. return null; }, visitDefinedType(node, { self }) { if (visitedDefinedTypes.has(node.name)) { return visitedDefinedTypes.get(node.name)!; } definedTypeStack.push(node.name); const child = visit(node.type, self); definedTypeStack.pop(); visitedDefinedTypes.set(node.name, child); return child; }, visitDefinedTypeLink(node, { self }) { // Fetch the linked type and return null if not found. const linkedDefinedPath = linkables.getPath(stack.getPath(node.kind)); if (!linkedDefinedPath) return null; const linkedDefinedType = getLastNodeFromPath(linkedDefinedPath); // This prevents infinite recursion by assuming cyclic types don't have a fixed size. if (definedTypeStack.includes(linkedDefinedType.name)) return null; stack.pushPath(linkedDefinedPath); const result = visit(linkedDefinedType, self); stack.popPath(); return result; }, visitEnumEmptyVariantType() { return 0; }, visitEnumType(node, { self }) { const prefix = visit(node.size, self); if (prefix === null) return null; if (isScalarEnum(node)) return prefix; const variantSizes = node.variants.map(v => visit(v, self)); const allVariantHaveTheSameFixedSize = variantSizes.every((one, _, all) => one === all[0]); return allVariantHaveTheSameFixedSize && variantSizes.length > 0 && variantSizes[0] !== null ? variantSizes[0] + prefix : null; }, visitFixedSizeType(node) { return node.size; }, visitInstruction(node, { self }) { return sumSizes(node.arguments.map(arg => visit(arg, self))); }, visitInstructionArgument(node, { self }) { return visit(node.type, self); }, visitMapType(node, { self }) { const innerSize = sumSizes([visit(node.key, self), visit(node.value, self)]); return getArrayLikeSize(node.count, innerSize, self); }, visitNumberType(node) { if (node.format === 'shortU16') return null; return parseInt(node.format.slice(1), 10) / 8; }, visitOptionType(node, { self }) { if (!node.fixed) return null; return sumSizes([visit(node.prefix, self), visit(node.item, self)]); }, visitPostOffsetType(node, { self }) { const typeSize = visit(node.type, self); return node.strategy === 'padded' ? sumSizes([typeSize, node.offset]) : typeSize; }, visitPreOffsetType(node, { self }) { const typeSize = visit(node.type, self); return node.strategy === 'padded' ? sumSizes([typeSize, node.offset]) : typeSize; }, visitPublicKeyType() { return 32; }, visitRemainderOptionType(node, { self }) { const itemSize = visit(node.item, self); return itemSize === 0 ? 0 : null; }, visitSetType(node, { self }) { return getArrayLikeSize(node.count, visit(node.item, self), self); }, visitZeroableOptionType(node, { self }) { const itemSize = visit(node.item, self); if (!node.zeroValue) return itemSize; const zeroSize = visit(node.zeroValue, self); return zeroSize === itemSize ? itemSize : null; }, }), v => recordNodeStackVisitor(v, stack), ); } function getArrayLikeSize( count: CountNode, innerSize: number | null, self: Visitor, ): number | null { if (innerSize === 0 && isNode(count, 'prefixedCountNode')) return visit(count.prefix, self); if (innerSize === 0) return 0; if (!isNode(count, 'fixedCountNode')) return null; if (count.value === 0) return 0; return innerSize !== null ? innerSize * count.value : null; } ================================================ FILE: packages/visitors-core/src/getDebugStringVisitor.ts ================================================ import { Node } from '@codama/nodes'; import { interceptVisitor } from './interceptVisitor'; import { mergeVisitor } from './mergeVisitor'; import { pipe } from './pipe'; import { Visitor } from './visitor'; export function getDebugStringVisitor(options: { indent?: boolean; indentSeparator?: string } = {}): Visitor { const indent = options.indent ?? false; const indentSeparator = options.indentSeparator ?? '| '; let stackLevel = -1; return pipe( mergeVisitor( node => { const details = getNodeDetails(node).join('.'); if (indent) { return `${indentSeparator.repeat(stackLevel)}${node.kind}${details ? ` [${details}]` : ''}`; } return `${node.kind}${details ? `[${details}]` : ''}`; }, (node, values) => { const details = getNodeDetails(node).join('.'); if (indent) { return [ `${indentSeparator.repeat(stackLevel)}${node.kind}${details ? ` [${details}]` : ''}`, ...values, ].join('\n'); } return `${node.kind}${details ? `[${details}]` : ''}(${values.join(', ')})`; }, ), v => interceptVisitor(v, (node, next) => { stackLevel += 1; const newNode = next(node); stackLevel -= 1; return newNode; }), ); } function getNodeDetails(node: Node): string[] { switch (node.kind) { case 'programNode': return [node.name, node.publicKey]; case 'instructionAccountNode': return [ node.name, ...(node.isWritable ? ['writable'] : []), ...(node.isSigner === true ? ['signer'] : []), ...(node.isSigner === 'either' ? ['optionalSigner'] : []), ...(node.isOptional ? ['optional'] : []), ]; case 'instructionRemainingAccountsNode': return [ ...(node.isOptional ? ['optional'] : []), ...(node.isWritable ? ['writable'] : []), ...(node.isSigner === true ? ['signer'] : []), ...(node.isSigner === 'either' ? ['optionalSigner'] : []), ]; case 'instructionByteDeltaNode': return [...(node.subtract ? ['subtract'] : []), ...(node.withHeader ? ['withHeader'] : [])]; case 'instructionStatusNode': return [node.lifecycle, ...(node.message ? [node.message] : [])]; case 'errorNode': return [node.code.toString(), node.name]; case 'accountLinkNode': case 'definedTypeLinkNode': case 'instructionAccountLinkNode': case 'instructionArgumentLinkNode': case 'instructionLinkNode': case 'pdaLinkNode': case 'programLinkNode': return [node.name]; case 'numberTypeNode': return [node.format, ...(node.endian === 'be' ? ['bigEndian'] : [])]; case 'amountTypeNode': return [node.decimals.toString(), ...(node.unit ? [node.unit] : [])]; case 'stringTypeNode': return [node.encoding]; case 'optionTypeNode': return node.fixed ? ['fixed'] : []; case 'fixedCountNode': return [node.value.toString()]; case 'numberValueNode': return [node.number.toString()]; case 'stringValueNode': return [node.string]; case 'booleanValueNode': return [node.boolean ? 'true' : 'false']; case 'bytesValueNode': return [node.encoding, node.data]; case 'publicKeyValueNode': return [...(node.identifier ? [`${node.identifier}`] : []), node.publicKey]; case 'enumValueNode': return [node.variant]; case 'resolverValueNode': return [node.name]; case 'constantDiscriminatorNode': return [...(node.offset > 0 ? [`offset:${node.offset}`] : [])]; case 'fieldDiscriminatorNode': return [node.name, ...(node.offset > 0 ? [`offset:${node.offset}`] : [])]; case 'sizeDiscriminatorNode': return [node.size.toString()]; case 'fixedSizeTypeNode': return [node.size.toString()]; case 'preOffsetTypeNode': return [node.offset.toString(), node.strategy ?? 'relative']; case 'postOffsetTypeNode': return [node.offset.toString(), node.strategy ?? 'relative']; default: return 'name' in node ? [node.name] : []; } } ================================================ FILE: packages/visitors-core/src/getMaxByteSizeVisitor.ts ================================================ import { CountNode, isNode, isScalarEnum, REGISTERED_TYPE_NODE_KINDS } from '@codama/nodes'; import { extendVisitor } from './extendVisitor'; import { ByteSizeVisitorKeys } from './getByteSizeVisitor'; import { LinkableDictionary } from './LinkableDictionary'; import { mergeVisitor } from './mergeVisitor'; import { getLastNodeFromPath } from './NodePath'; import { NodeStack } from './NodeStack'; import { pipe } from './pipe'; import { recordNodeStackVisitor } from './recordNodeStackVisitor'; import { visit, Visitor } from './visitor'; export function getMaxByteSizeVisitor( linkables: LinkableDictionary, options: { stack?: NodeStack } = {}, ): Visitor { const stack = options.stack ?? new NodeStack(); const visitedDefinedTypes = new Map(); const definedTypeStack: string[] = []; const sumSizes = (values: (number | null)[]): number | null => values.reduce((all, one) => (all === null || one === null ? null : all + one), 0 as number | null); const baseVisitor = mergeVisitor( () => null as number | null, (_, values) => sumSizes(values), { keys: [ ...REGISTERED_TYPE_NODE_KINDS, 'accountNode', 'constantValueNode', 'definedTypeLinkNode', 'definedTypeNode', 'instructionArgumentNode', 'instructionNode', ], }, ); return pipe( baseVisitor, v => extendVisitor(v, { visitAccount(node, { self }) { return visit(node.data, self); }, visitArrayType(node, { self }) { return getArrayLikeSize(node.count, visit(node.item, self), self); }, visitConstantValue(node, { self }) { const typeSize = visit(node.type, self); if (typeSize !== null) return typeSize; if (isNode(node.value, 'bytesValueNode') && node.value.encoding === 'base16') { return Math.ceil(node.value.data.length / 2); } if ( isNode(node.type, 'stringTypeNode') && node.type.encoding === 'base16' && isNode(node.value, 'stringValueNode') ) { return Math.ceil(node.value.string.length / 2); } // Technically, we could still identify other fixed-size constants // but we'd need to import @solana/codecs to compute them. return null; }, visitDefinedType(node, { self }) { if (visitedDefinedTypes.has(node.name)) { return visitedDefinedTypes.get(node.name)!; } definedTypeStack.push(node.name); const child = visit(node.type, self); definedTypeStack.pop(); visitedDefinedTypes.set(node.name, child); return child; }, visitDefinedTypeLink(node, { self }) { // Fetch the linked type and return null if not found. const linkedDefinedPath = linkables.getPath(stack.getPath(node.kind)); if (!linkedDefinedPath) return null; const linkedDefinedType = getLastNodeFromPath(linkedDefinedPath); // This prevents infinite recursion by assuming cyclic types don't have a fixed size. if (definedTypeStack.includes(linkedDefinedType.name)) return null; stack.pushPath(linkedDefinedPath); const result = visit(linkedDefinedType, self); stack.popPath(); return result; }, visitEnumEmptyVariantType() { return 0; }, visitEnumType(node, { self }) { const prefix = visit(node.size, self); if (prefix === null) return null; if (isScalarEnum(node)) return prefix; const variantSizes = node.variants.map(v => visit(v, self)); if (variantSizes.includes(null)) return null; const maxVariantSize = Math.max(...(variantSizes as number[])); return prefix + maxVariantSize; }, visitFixedSizeType(node) { return node.size; }, visitInstruction(node, { self }) { return sumSizes(node.arguments.map(arg => visit(arg, self))); }, visitInstructionArgument(node, { self }) { return visit(node.type, self); }, visitMapType(node, { self }) { const innerSize = sumSizes([visit(node.key, self), visit(node.value, self)]); return getArrayLikeSize(node.count, innerSize, self); }, visitNumberType(node) { if (node.format === 'shortU16') return 3; return parseInt(node.format.slice(1), 10) / 8; }, visitOptionType(node, { self }) { return sumSizes([visit(node.prefix, self), visit(node.item, self)]); }, visitPostOffsetType(node, { self }) { const typeSize = visit(node.type, self); return node.strategy === 'padded' ? sumSizes([typeSize, node.offset]) : typeSize; }, visitPreOffsetType(node, { self }) { const typeSize = visit(node.type, self); return node.strategy === 'padded' ? sumSizes([typeSize, node.offset]) : typeSize; }, visitPublicKeyType() { return 32; }, visitRemainderOptionType(node, { self }) { const itemSize = visit(node.item, self); return itemSize === 0 ? 0 : null; }, visitSetType(node, { self }) { return getArrayLikeSize(node.count, visit(node.item, self), self); }, visitZeroableOptionType(node, { self }) { const itemSize = visit(node.item, self); if (!node.zeroValue) return itemSize; const zeroSize = visit(node.zeroValue, self); if (itemSize === null || zeroSize === null) return null; return Math.max(itemSize, zeroSize); }, }), v => recordNodeStackVisitor(v, stack), ); } function getArrayLikeSize( count: CountNode, innerSize: number | null, self: Visitor, ): number | null { if (innerSize === 0 && isNode(count, 'prefixedCountNode')) return visit(count.prefix, self); if (innerSize === 0) return 0; if (!isNode(count, 'fixedCountNode')) return null; if (count.value === 0) return 0; return innerSize !== null ? innerSize * count.value : null; } ================================================ FILE: packages/visitors-core/src/getResolvedInstructionInputsVisitor.ts ================================================ /* eslint-disable no-case-declarations */ import { CODAMA_ERROR__VISITORS__CANNOT_USE_OPTIONAL_ACCOUNT_AS_PDA_SEED_VALUE, CODAMA_ERROR__VISITORS__CYCLIC_DEPENDENCY_DETECTED_WHEN_RESOLVING_INSTRUCTION_DEFAULT_VALUES, CODAMA_ERROR__VISITORS__INVALID_INSTRUCTION_DEFAULT_VALUE_DEPENDENCY, CodamaError, } from '@codama/errors'; import { AccountValueNode, accountValueNode, ArgumentValueNode, argumentValueNode, CamelCaseString, getAllInstructionArguments, InstructionAccountNode, InstructionArgumentNode, InstructionInputValueNode, InstructionNode, isNode, VALUE_NODES, } from '@codama/nodes'; import { singleNodeVisitor } from './singleNodeVisitor'; import { Visitor } from './visitor'; export type ResolvedInstructionInput = ResolvedInstructionAccount | ResolvedInstructionArgument; export type ResolvedInstructionAccount = InstructionAccountNode & { dependsOn: InstructionDependency[]; isPda: boolean; resolvedIsOptional: boolean; resolvedIsSigner: boolean | 'either'; }; export type ResolvedInstructionArgument = InstructionArgumentNode & { dependsOn: InstructionDependency[]; }; type InstructionInput = InstructionAccountNode | InstructionArgumentNode; type InstructionDependency = AccountValueNode | ArgumentValueNode; export function getResolvedInstructionInputsVisitor( options: { includeDataArgumentValueNodes?: boolean } = {}, ): Visitor { const includeDataArgumentValueNodes = options.includeDataArgumentValueNodes ?? false; let stack: InstructionInput[] = []; let resolved: ResolvedInstructionInput[] = []; let visitedAccounts = new Map(); let visitedArgs = new Map(); function resolveInstructionInput(instruction: InstructionNode, input: InstructionInput): void { // Ensure we don't visit the same input twice. if ( (isNode(input, 'instructionAccountNode') && visitedAccounts.has(input.name)) || (isNode(input, 'instructionArgumentNode') && visitedArgs.has(input.name)) ) { return; } // Ensure we don't have a circular dependency. const isCircular = stack.some(({ kind, name }) => kind === input.kind && name === input.name); if (isCircular) { const cycle = [...stack, input]; throw new CodamaError( CODAMA_ERROR__VISITORS__CYCLIC_DEPENDENCY_DETECTED_WHEN_RESOLVING_INSTRUCTION_DEFAULT_VALUES, { cycle, formattedCycle: cycle.map(({ name }) => name).join(' -> '), instruction, instructionName: instruction.name, }, ); } // Resolve whilst keeping track of the stack. stack.push(input); const localResolved = input.kind === 'instructionAccountNode' ? resolveInstructionAccount(instruction, input) : resolveInstructionArgument(instruction, input); stack.pop(); // Store the resolved input. resolved.push(localResolved); if (localResolved.kind === 'instructionAccountNode') { visitedAccounts.set(input.name, localResolved); } else { visitedArgs.set(input.name, localResolved); } } function resolveInstructionAccount( instruction: InstructionNode, account: InstructionAccountNode, ): ResolvedInstructionAccount { // Find and visit dependencies first. const dependsOn = getInstructionDependencies(account); resolveInstructionDependencies(instruction, account, dependsOn); const localResolved: ResolvedInstructionAccount = { ...account, dependsOn, isPda: getAllInstructionArguments(instruction).some( argument => isNode(argument.defaultValue, 'accountBumpValueNode') && argument.defaultValue.name === account.name, ), resolvedIsOptional: !!account.isOptional, resolvedIsSigner: account.isSigner, }; switch (localResolved.defaultValue?.kind) { case 'accountValueNode': const defaultAccount = visitedAccounts.get(localResolved.defaultValue.name)!; const resolvedIsPublicKey = account.isSigner === false && defaultAccount.isSigner === false; const resolvedIsSigner = account.isSigner === true && defaultAccount.isSigner === true; const resolvedIsOptionalSigner = !resolvedIsPublicKey && !resolvedIsSigner; localResolved.resolvedIsSigner = resolvedIsOptionalSigner ? 'either' : resolvedIsSigner; localResolved.resolvedIsOptional = !!defaultAccount.isOptional; break; case 'publicKeyValueNode': case 'programLinkNode': case 'programIdValueNode': localResolved.resolvedIsSigner = account.isSigner === false ? false : 'either'; localResolved.resolvedIsOptional = false; break; case 'pdaValueNode': localResolved.resolvedIsSigner = account.isSigner === false ? false : 'either'; localResolved.resolvedIsOptional = false; const { seeds } = localResolved.defaultValue; seeds.forEach(seed => { if (!isNode(seed.value, 'accountValueNode')) return; const dependency = visitedAccounts.get(seed.value.name)!; if (dependency.resolvedIsOptional) { throw new CodamaError(CODAMA_ERROR__VISITORS__CANNOT_USE_OPTIONAL_ACCOUNT_AS_PDA_SEED_VALUE, { instruction: instruction, instructionAccount: account, instructionAccountName: account.name, instructionName: instruction.name, seed, seedName: seed.name, seedValueName: seed.value.name, }); } }); break; case 'identityValueNode': case 'payerValueNode': case 'resolverValueNode': localResolved.resolvedIsOptional = false; break; default: break; } return localResolved; } function resolveInstructionArgument( instruction: InstructionNode, argument: InstructionArgumentNode, ): ResolvedInstructionArgument { // Find and visit dependencies first. const dependsOn = getInstructionDependencies(argument); resolveInstructionDependencies(instruction, argument, dependsOn); return { ...argument, dependsOn }; } function resolveInstructionDependencies( instruction: InstructionNode, parent: InstructionInput, dependencies: InstructionDependency[], ): void { dependencies.forEach(dependency => { let input: InstructionInput | null = null; if (isNode(dependency, 'accountValueNode')) { const dependencyAccount = instruction.accounts.find(a => a.name === dependency.name); if (!dependencyAccount) { throw new CodamaError(CODAMA_ERROR__VISITORS__INVALID_INSTRUCTION_DEFAULT_VALUE_DEPENDENCY, { dependency, dependencyKind: dependency.kind, dependencyName: dependency.name, instruction, instructionName: instruction.name, parent, parentKind: parent.kind, parentName: parent.name, }); } input = { ...dependencyAccount }; } else if (isNode(dependency, 'argumentValueNode')) { const dependencyArgument = getAllInstructionArguments(instruction).find( a => a.name === dependency.name, ); if (!dependencyArgument) { throw new CodamaError(CODAMA_ERROR__VISITORS__INVALID_INSTRUCTION_DEFAULT_VALUE_DEPENDENCY, { dependency, dependencyKind: dependency.kind, dependencyName: dependency.name, instruction, instructionName: instruction.name, parent, parentKind: parent.kind, parentName: parent.name, }); } input = { ...dependencyArgument }; } if (input) { resolveInstructionInput(instruction, input); } }); } return singleNodeVisitor('instructionNode', (node): ResolvedInstructionInput[] => { // Ensure we always start with a clean slate. stack = []; resolved = []; visitedAccounts = new Map(); visitedArgs = new Map(); const inputs: InstructionInput[] = [ ...node.accounts, ...node.arguments.filter(a => { if (includeDataArgumentValueNodes) return a.defaultValue; return a.defaultValue && !isNode(a.defaultValue, VALUE_NODES); }), ...(node.extraArguments ?? []).filter(a => a.defaultValue), ]; // Visit all instruction accounts. inputs.forEach(input => { resolveInstructionInput(node, input); }); return resolved; }); } export function deduplicateInstructionDependencies(dependencies: InstructionDependency[]): InstructionDependency[] { const accounts = new Map(); const args = new Map(); dependencies.forEach(dependency => { if (isNode(dependency, 'accountValueNode')) { accounts.set(dependency.name, dependency); } else if (isNode(dependency, 'argumentValueNode')) { args.set(dependency.name, dependency); } }); return [...accounts.values(), ...args.values()]; } export function getInstructionDependencies(input: InstructionInput | InstructionNode): InstructionDependency[] { if (isNode(input, 'instructionNode')) { return deduplicateInstructionDependencies([ ...input.accounts.flatMap(getInstructionDependencies), ...input.arguments.flatMap(getInstructionDependencies), ...(input.extraArguments ?? []).flatMap(getInstructionDependencies), ]); } if (!input.defaultValue) return []; const getNestedDependencies = (defaultValue: InstructionInputValueNode | undefined): InstructionDependency[] => { if (!defaultValue) return []; return getInstructionDependencies({ ...input, defaultValue }); }; if (isNode(input.defaultValue, ['accountValueNode', 'accountBumpValueNode'])) { return [accountValueNode(input.defaultValue.name)]; } if (isNode(input.defaultValue, ['argumentValueNode'])) { return [argumentValueNode(input.defaultValue.name)]; } if (isNode(input.defaultValue, 'pdaValueNode')) { const dependencies = new Map(); input.defaultValue.seeds.forEach(seed => { if (isNode(seed.value, ['accountValueNode', 'argumentValueNode'])) { dependencies.set(seed.value.name, { ...seed.value }); } }); return [ ...dependencies.values(), ...(input.defaultValue.programId ? ([input.defaultValue.programId] as const) : []), ]; } if (isNode(input.defaultValue, 'resolverValueNode')) { return input.defaultValue.dependsOn ?? []; } if (isNode(input.defaultValue, 'conditionalValueNode')) { return deduplicateInstructionDependencies([ ...getNestedDependencies(input.defaultValue.condition), ...getNestedDependencies(input.defaultValue.ifTrue), ...getNestedDependencies(input.defaultValue.ifFalse), ]); } return []; } ================================================ FILE: packages/visitors-core/src/getUniqueHashStringVisitor.ts ================================================ import stringify from 'json-stable-stringify'; import { mapVisitor } from './mapVisitor'; import { removeDocsVisitor } from './removeDocsVisitor'; import { staticVisitor } from './staticVisitor'; import { Visitor } from './visitor'; export function getUniqueHashStringVisitor(options: { removeDocs?: boolean } = {}): Visitor { const removeDocs = options.removeDocs ?? false; if (!removeDocs) { return staticVisitor(node => stringify(node) as string); } return mapVisitor(removeDocsVisitor(), node => stringify(node) as string); } ================================================ FILE: packages/visitors-core/src/identityVisitor.ts ================================================ import { accountLinkNode, accountNode, amountTypeNode, arrayTypeNode, arrayValueNode, assertIsNestedTypeNode, assertIsNode, booleanTypeNode, conditionalValueNode, constantDiscriminatorNode, constantPdaSeedNode, constantValueNode, COUNT_NODES, dateTimeTypeNode, definedTypeLinkNode, definedTypeNode, DISCRIMINATOR_NODES, ENUM_VARIANT_TYPE_NODES, enumEmptyVariantTypeNode, enumStructVariantTypeNode, enumTupleVariantTypeNode, enumTypeNode, enumValueNode, eventNode, fixedSizeTypeNode, hiddenPrefixTypeNode, hiddenSuffixTypeNode, INSTRUCTION_INPUT_VALUE_NODES, instructionAccountLinkNode, instructionAccountNode, instructionArgumentLinkNode, instructionArgumentNode, instructionByteDeltaNode, instructionLinkNode, instructionNode, instructionRemainingAccountsNode, instructionStatusNode, mapEntryValueNode, mapTypeNode, mapValueNode, Node, NodeKind, optionTypeNode, PDA_SEED_NODES, pdaLinkNode, pdaNode, pdaSeedValueNode, pdaValueNode, postOffsetTypeNode, prefixedCountNode, preOffsetTypeNode, programNode, REGISTERED_NODE_KINDS, remainderOptionTypeNode, removeNullAndAssertIsNodeFilter, resolverValueNode, rootNode, sentinelTypeNode, setTypeNode, setValueNode, sizePrefixTypeNode, solAmountTypeNode, someValueNode, structFieldTypeNode, structFieldValueNode, structTypeNode, structValueNode, tupleTypeNode, tupleValueNode, TYPE_NODES, VALUE_NODES, variablePdaSeedNode, zeroableOptionTypeNode, } from '@codama/nodes'; import { staticVisitor } from './staticVisitor'; import { visit as baseVisit, Visitor } from './visitor'; export function identityVisitor( options: { keys?: TNodeKind[] } = {}, ): Visitor { const keys: NodeKind[] = options.keys ?? (REGISTERED_NODE_KINDS as TNodeKind[]); const visitor = staticVisitor(node => Object.freeze({ ...node }), { keys }) as Visitor; const visit = (v: Visitor) => (node: Node): Node | null => keys.includes(node.kind) ? baseVisit(node, v) : Object.freeze({ ...node }); if (keys.includes('rootNode')) { visitor.visitRoot = function visitRoot(node) { const program = visit(this)(node.program); if (program === null) return null; assertIsNode(program, 'programNode'); return rootNode( program, node.additionalPrograms.map(visit(this)).filter(removeNullAndAssertIsNodeFilter('programNode')), ); }; } if (keys.includes('programNode')) { visitor.visitProgram = function visitProgram(node) { return programNode({ ...node, accounts: node.accounts.map(visit(this)).filter(removeNullAndAssertIsNodeFilter('accountNode')), definedTypes: node.definedTypes .map(visit(this)) .filter(removeNullAndAssertIsNodeFilter('definedTypeNode')), errors: node.errors.map(visit(this)).filter(removeNullAndAssertIsNodeFilter('errorNode')), events: (node.events ?? []).map(visit(this)).filter(removeNullAndAssertIsNodeFilter('eventNode')), instructions: node.instructions .map(visit(this)) .filter(removeNullAndAssertIsNodeFilter('instructionNode')), pdas: node.pdas.map(visit(this)).filter(removeNullAndAssertIsNodeFilter('pdaNode')), }); }; } if (keys.includes('pdaNode')) { visitor.visitPda = function visitPda(node) { return pdaNode({ ...node, seeds: node.seeds.map(visit(this)).filter(removeNullAndAssertIsNodeFilter(PDA_SEED_NODES)), }); }; } if (keys.includes('accountNode')) { visitor.visitAccount = function visitAccount(node) { const data = visit(this)(node.data); if (data === null) return null; assertIsNode(data, 'structTypeNode'); const pda = node.pda ? (visit(this)(node.pda) ?? undefined) : undefined; if (pda) assertIsNode(pda, 'pdaLinkNode'); return accountNode({ ...node, data, pda }); }; } if (keys.includes('eventNode')) { visitor.visitEvent = function visitEvent(node) { const data = visit(this)(node.data); if (data === null) return null; assertIsNode(data, TYPE_NODES); return eventNode({ ...node, data, discriminators: node.discriminators ? node.discriminators.map(visit(this)).filter(removeNullAndAssertIsNodeFilter(DISCRIMINATOR_NODES)) : undefined, }); }; } if (keys.includes('instructionNode')) { visitor.visitInstruction = function visitInstruction(node) { const status = node.status ? (visit(this)(node.status) ?? undefined) : undefined; if (status) assertIsNode(status, 'instructionStatusNode'); return instructionNode({ ...node, accounts: node.accounts .map(visit(this)) .filter(removeNullAndAssertIsNodeFilter('instructionAccountNode')), arguments: node.arguments .map(visit(this)) .filter(removeNullAndAssertIsNodeFilter('instructionArgumentNode')), byteDeltas: node.byteDeltas ? node.byteDeltas .map(visit(this)) .filter(removeNullAndAssertIsNodeFilter('instructionByteDeltaNode')) : undefined, discriminators: node.discriminators ? node.discriminators.map(visit(this)).filter(removeNullAndAssertIsNodeFilter(DISCRIMINATOR_NODES)) : undefined, extraArguments: node.extraArguments ? node.extraArguments .map(visit(this)) .filter(removeNullAndAssertIsNodeFilter('instructionArgumentNode')) : undefined, remainingAccounts: node.remainingAccounts ? node.remainingAccounts .map(visit(this)) .filter(removeNullAndAssertIsNodeFilter('instructionRemainingAccountsNode')) : undefined, status, subInstructions: node.subInstructions ? node.subInstructions.map(visit(this)).filter(removeNullAndAssertIsNodeFilter('instructionNode')) : undefined, }); }; } if (keys.includes('instructionAccountNode')) { visitor.visitInstructionAccount = function visitInstructionAccount(node) { const defaultValue = node.defaultValue ? (visit(this)(node.defaultValue) ?? undefined) : undefined; if (defaultValue) assertIsNode(defaultValue, INSTRUCTION_INPUT_VALUE_NODES); return instructionAccountNode({ ...node, defaultValue }); }; } if (keys.includes('instructionArgumentNode')) { visitor.visitInstructionArgument = function visitInstructionArgument(node) { const type = visit(this)(node.type); if (type === null) return null; assertIsNode(type, TYPE_NODES); const defaultValue = node.defaultValue ? (visit(this)(node.defaultValue) ?? undefined) : undefined; if (defaultValue) assertIsNode(defaultValue, INSTRUCTION_INPUT_VALUE_NODES); return instructionArgumentNode({ ...node, defaultValue, type }); }; } if (keys.includes('instructionRemainingAccountsNode')) { visitor.visitInstructionRemainingAccounts = function visitInstructionRemainingAccounts(node) { const value = visit(this)(node.value); if (value === null) return null; assertIsNode(value, ['argumentValueNode', 'resolverValueNode']); return instructionRemainingAccountsNode(value, { ...node }); }; } if (keys.includes('instructionByteDeltaNode')) { visitor.visitInstructionByteDelta = function visitInstructionByteDelta(node) { const value = visit(this)(node.value); if (value === null) return null; assertIsNode(value, ['numberValueNode', 'accountLinkNode', 'argumentValueNode', 'resolverValueNode']); return instructionByteDeltaNode(value, { ...node }); }; } if (keys.includes('instructionStatusNode')) { visitor.visitInstructionStatus = function visitInstructionStatus(node) { return instructionStatusNode(node.lifecycle, node.message); }; } if (keys.includes('definedTypeNode')) { visitor.visitDefinedType = function visitDefinedType(node) { const type = visit(this)(node.type); if (type === null) return null; assertIsNode(type, TYPE_NODES); return definedTypeNode({ ...node, type }); }; } if (keys.includes('arrayTypeNode')) { visitor.visitArrayType = function visitArrayType(node) { const size = visit(this)(node.count); if (size === null) return null; assertIsNode(size, COUNT_NODES); const item = visit(this)(node.item); if (item === null) return null; assertIsNode(item, TYPE_NODES); return arrayTypeNode(item, size); }; } if (keys.includes('enumTypeNode')) { visitor.visitEnumType = function visitEnumType(node) { return enumTypeNode( node.variants.map(visit(this)).filter(removeNullAndAssertIsNodeFilter(ENUM_VARIANT_TYPE_NODES)), { size: node.size }, ); }; } if (keys.includes('enumStructVariantTypeNode')) { visitor.visitEnumStructVariantType = function visitEnumStructVariantType(node) { const newStruct = visit(this)(node.struct); if (!newStruct) { return enumEmptyVariantTypeNode(node.name); } assertIsNode(newStruct, 'structTypeNode'); if (newStruct.fields.length === 0) { return enumEmptyVariantTypeNode(node.name); } return enumStructVariantTypeNode(node.name, newStruct); }; } if (keys.includes('enumTupleVariantTypeNode')) { visitor.visitEnumTupleVariantType = function visitEnumTupleVariantType(node) { const newTuple = visit(this)(node.tuple); if (!newTuple) { return enumEmptyVariantTypeNode(node.name); } assertIsNode(newTuple, 'tupleTypeNode'); if (newTuple.items.length === 0) { return enumEmptyVariantTypeNode(node.name); } return enumTupleVariantTypeNode(node.name, newTuple); }; } if (keys.includes('mapTypeNode')) { visitor.visitMapType = function visitMapType(node) { const size = visit(this)(node.count); if (size === null) return null; assertIsNode(size, COUNT_NODES); const key = visit(this)(node.key); if (key === null) return null; assertIsNode(key, TYPE_NODES); const value = visit(this)(node.value); if (value === null) return null; assertIsNode(value, TYPE_NODES); return mapTypeNode(key, value, size); }; } if (keys.includes('optionTypeNode')) { visitor.visitOptionType = function visitOptionType(node) { const prefix = visit(this)(node.prefix); if (prefix === null) return null; assertIsNestedTypeNode(prefix, 'numberTypeNode'); const item = visit(this)(node.item); if (item === null) return null; assertIsNode(item, TYPE_NODES); return optionTypeNode(item, { ...node, prefix }); }; } if (keys.includes('zeroableOptionTypeNode')) { visitor.visitZeroableOptionType = function visitZeroableOptionType(node) { const item = visit(this)(node.item); if (item === null) return null; assertIsNode(item, TYPE_NODES); const zeroValue = node.zeroValue ? (visit(this)(node.zeroValue) ?? undefined) : undefined; if (zeroValue) assertIsNode(zeroValue, 'constantValueNode'); return zeroableOptionTypeNode(item, zeroValue); }; } if (keys.includes('remainderOptionTypeNode')) { visitor.visitRemainderOptionType = function visitRemainderOptionType(node) { const item = visit(this)(node.item); if (item === null) return null; assertIsNode(item, TYPE_NODES); return remainderOptionTypeNode(item); }; } if (keys.includes('booleanTypeNode')) { visitor.visitBooleanType = function visitBooleanType(node) { const size = visit(this)(node.size); if (size === null) return null; assertIsNestedTypeNode(size, 'numberTypeNode'); return booleanTypeNode(size); }; } if (keys.includes('setTypeNode')) { visitor.visitSetType = function visitSetType(node) { const size = visit(this)(node.count); if (size === null) return null; assertIsNode(size, COUNT_NODES); const item = visit(this)(node.item); if (item === null) return null; assertIsNode(item, TYPE_NODES); return setTypeNode(item, size); }; } if (keys.includes('structTypeNode')) { visitor.visitStructType = function visitStructType(node) { const fields = node.fields.map(visit(this)).filter(removeNullAndAssertIsNodeFilter('structFieldTypeNode')); return structTypeNode(fields); }; } if (keys.includes('structFieldTypeNode')) { visitor.visitStructFieldType = function visitStructFieldType(node) { const type = visit(this)(node.type); if (type === null) return null; assertIsNode(type, TYPE_NODES); const defaultValue = node.defaultValue ? (visit(this)(node.defaultValue) ?? undefined) : undefined; if (defaultValue) assertIsNode(defaultValue, VALUE_NODES); return structFieldTypeNode({ ...node, defaultValue, type }); }; } if (keys.includes('tupleTypeNode')) { visitor.visitTupleType = function visitTupleType(node) { const items = node.items.map(visit(this)).filter(removeNullAndAssertIsNodeFilter(TYPE_NODES)); return tupleTypeNode(items); }; } if (keys.includes('amountTypeNode')) { visitor.visitAmountType = function visitAmountType(node) { const number = visit(this)(node.number); if (number === null) return null; assertIsNestedTypeNode(number, 'numberTypeNode'); return amountTypeNode(number, node.decimals, node.unit); }; } if (keys.includes('dateTimeTypeNode')) { visitor.visitDateTimeType = function visitDateTimeType(node) { const number = visit(this)(node.number); if (number === null) return null; assertIsNestedTypeNode(number, 'numberTypeNode'); return dateTimeTypeNode(number); }; } if (keys.includes('solAmountTypeNode')) { visitor.visitSolAmountType = function visitSolAmountType(node) { const number = visit(this)(node.number); if (number === null) return null; assertIsNestedTypeNode(number, 'numberTypeNode'); return solAmountTypeNode(number); }; } if (keys.includes('prefixedCountNode')) { visitor.visitPrefixedCount = function visitPrefixedCount(node) { const prefix = visit(this)(node.prefix); if (prefix === null) return null; assertIsNestedTypeNode(prefix, 'numberTypeNode'); return prefixedCountNode(prefix); }; } if (keys.includes('arrayValueNode')) { visitor.visitArrayValue = function visitArrayValue(node) { return arrayValueNode(node.items.map(visit(this)).filter(removeNullAndAssertIsNodeFilter(VALUE_NODES))); }; } if (keys.includes('constantValueNode')) { visitor.visitConstantValue = function visitConstantValue(node) { const type = visit(this)(node.type); if (type === null) return null; assertIsNode(type, TYPE_NODES); const value = visit(this)(node.value); if (value === null) return null; assertIsNode(value, VALUE_NODES); return constantValueNode(type, value); }; } if (keys.includes('enumValueNode')) { visitor.visitEnumValue = function visitEnumValue(node) { const enumLink = visit(this)(node.enum); if (enumLink === null) return null; assertIsNode(enumLink, ['definedTypeLinkNode']); const value = node.value ? (visit(this)(node.value) ?? undefined) : undefined; if (value) assertIsNode(value, ['structValueNode', 'tupleValueNode']); return enumValueNode(enumLink, node.variant, value); }; } if (keys.includes('mapValueNode')) { visitor.visitMapValue = function visitMapValue(node) { return mapValueNode( node.entries.map(visit(this)).filter(removeNullAndAssertIsNodeFilter('mapEntryValueNode')), ); }; } if (keys.includes('mapEntryValueNode')) { visitor.visitMapEntryValue = function visitMapEntryValue(node) { const key = visit(this)(node.key); if (key === null) return null; assertIsNode(key, VALUE_NODES); const value = visit(this)(node.value); if (value === null) return null; assertIsNode(value, VALUE_NODES); return mapEntryValueNode(key, value); }; } if (keys.includes('setValueNode')) { visitor.visitSetValue = function visitSetValue(node) { return setValueNode(node.items.map(visit(this)).filter(removeNullAndAssertIsNodeFilter(VALUE_NODES))); }; } if (keys.includes('someValueNode')) { visitor.visitSomeValue = function visitSomeValue(node) { const value = visit(this)(node.value); if (value === null) return null; assertIsNode(value, VALUE_NODES); return someValueNode(value); }; } if (keys.includes('structValueNode')) { visitor.visitStructValue = function visitStructValue(node) { return structValueNode( node.fields.map(visit(this)).filter(removeNullAndAssertIsNodeFilter('structFieldValueNode')), ); }; } if (keys.includes('structFieldValueNode')) { visitor.visitStructFieldValue = function visitStructFieldValue(node) { const value = visit(this)(node.value); if (value === null) return null; assertIsNode(value, VALUE_NODES); return structFieldValueNode(node.name, value); }; } if (keys.includes('tupleValueNode')) { visitor.visitTupleValue = function visitTupleValue(node) { return tupleValueNode(node.items.map(visit(this)).filter(removeNullAndAssertIsNodeFilter(VALUE_NODES))); }; } if (keys.includes('constantPdaSeedNode')) { visitor.visitConstantPdaSeed = function visitConstantPdaSeed(node) { const type = visit(this)(node.type); if (type === null) return null; assertIsNode(type, TYPE_NODES); const value = visit(this)(node.value); if (value === null) return null; assertIsNode(value, [...VALUE_NODES, 'programIdValueNode']); return constantPdaSeedNode(type, value); }; } if (keys.includes('variablePdaSeedNode')) { visitor.visitVariablePdaSeed = function visitVariablePdaSeed(node) { const type = visit(this)(node.type); if (type === null) return null; assertIsNode(type, TYPE_NODES); return variablePdaSeedNode(node.name, type, node.docs); }; } if (keys.includes('resolverValueNode')) { visitor.visitResolverValue = function visitResolverValue(node) { const dependsOn = (node.dependsOn ?? []) .map(visit(this)) .filter(removeNullAndAssertIsNodeFilter(['accountValueNode', 'argumentValueNode'])); return resolverValueNode(node.name, { ...node, dependsOn: dependsOn.length === 0 ? undefined : dependsOn, }); }; } if (keys.includes('conditionalValueNode')) { visitor.visitConditionalValue = function visitConditionalValue(node) { const condition = visit(this)(node.condition); if (condition === null) return null; assertIsNode(condition, ['resolverValueNode', 'accountValueNode', 'argumentValueNode']); const value = node.value ? (visit(this)(node.value) ?? undefined) : undefined; if (value) assertIsNode(value, VALUE_NODES); const ifTrue = node.ifTrue ? (visit(this)(node.ifTrue) ?? undefined) : undefined; if (ifTrue) assertIsNode(ifTrue, INSTRUCTION_INPUT_VALUE_NODES); const ifFalse = node.ifFalse ? (visit(this)(node.ifFalse) ?? undefined) : undefined; if (ifFalse) assertIsNode(ifFalse, INSTRUCTION_INPUT_VALUE_NODES); if (!ifTrue && !ifFalse) return null; return conditionalValueNode({ condition, ifFalse, ifTrue, value }); }; } if (keys.includes('pdaValueNode')) { visitor.visitPdaValue = function visitPdaValue(node) { const pda = visit(this)(node.pda); if (pda === null) return null; assertIsNode(pda, ['pdaLinkNode', 'pdaNode']); const seeds = node.seeds.map(visit(this)).filter(removeNullAndAssertIsNodeFilter('pdaSeedValueNode')); return pdaValueNode(pda, seeds); }; } if (keys.includes('pdaSeedValueNode')) { visitor.visitPdaSeedValue = function visitPdaSeedValue(node) { const value = visit(this)(node.value); if (value === null) return null; assertIsNode(value, [...VALUE_NODES, 'accountValueNode', 'argumentValueNode']); return pdaSeedValueNode(node.name, value); }; } if (keys.includes('fixedSizeTypeNode')) { visitor.visitFixedSizeType = function visitFixedSizeType(node) { const type = visit(this)(node.type); if (type === null) return null; assertIsNode(type, TYPE_NODES); return fixedSizeTypeNode(type, node.size); }; } if (keys.includes('sizePrefixTypeNode')) { visitor.visitSizePrefixType = function visitSizePrefixType(node) { const prefix = visit(this)(node.prefix); if (prefix === null) return null; assertIsNestedTypeNode(prefix, 'numberTypeNode'); const type = visit(this)(node.type); if (type === null) return null; assertIsNode(type, TYPE_NODES); return sizePrefixTypeNode(type, prefix); }; } if (keys.includes('preOffsetTypeNode')) { visitor.visitPreOffsetType = function visitPreOffsetType(node) { const type = visit(this)(node.type); if (type === null) return null; assertIsNode(type, TYPE_NODES); return preOffsetTypeNode(type, node.offset, node.strategy); }; } if (keys.includes('postOffsetTypeNode')) { visitor.visitPostOffsetType = function visitPostOffsetType(node) { const type = visit(this)(node.type); if (type === null) return null; assertIsNode(type, TYPE_NODES); return postOffsetTypeNode(type, node.offset, node.strategy); }; } if (keys.includes('sentinelTypeNode')) { visitor.visitSentinelType = function visitSentinelType(node) { const sentinel = visit(this)(node.sentinel); if (sentinel === null) return null; assertIsNode(sentinel, 'constantValueNode'); const type = visit(this)(node.type); if (type === null) return null; assertIsNode(type, TYPE_NODES); return sentinelTypeNode(type, sentinel); }; } if (keys.includes('hiddenPrefixTypeNode')) { visitor.visitHiddenPrefixType = function visitHiddenPrefixType(node) { const type = visit(this)(node.type); if (type === null) return null; assertIsNode(type, TYPE_NODES); const prefix = node.prefix.map(visit(this)).filter(removeNullAndAssertIsNodeFilter('constantValueNode')); if (prefix.length === 0) return type; return hiddenPrefixTypeNode(type, prefix); }; } if (keys.includes('hiddenSuffixTypeNode')) { visitor.visitHiddenSuffixType = function visitHiddenSuffixType(node) { const type = visit(this)(node.type); if (type === null) return null; assertIsNode(type, TYPE_NODES); const suffix = node.suffix.map(visit(this)).filter(removeNullAndAssertIsNodeFilter('constantValueNode')); if (suffix.length === 0) return type; return hiddenSuffixTypeNode(type, suffix); }; } if (keys.includes('constantDiscriminatorNode')) { visitor.visitConstantDiscriminator = function visitConstantDiscriminator(node) { const constant = visit(this)(node.constant); if (constant === null) return null; assertIsNode(constant, 'constantValueNode'); return constantDiscriminatorNode(constant, node.offset); }; } if (keys.includes('accountLinkNode')) { visitor.visitAccountLink = function visitAccountLink(node) { const program = node.program ? (visit(this)(node.program) ?? undefined) : undefined; if (program) assertIsNode(program, 'programLinkNode'); return accountLinkNode(node.name, program); }; } if (keys.includes('definedTypeLinkNode')) { visitor.visitDefinedTypeLink = function visitDefinedTypeLink(node) { const program = node.program ? (visit(this)(node.program) ?? undefined) : undefined; if (program) assertIsNode(program, 'programLinkNode'); return definedTypeLinkNode(node.name, program); }; } if (keys.includes('instructionLinkNode')) { visitor.visitInstructionLink = function visitInstructionLink(node) { const program = node.program ? (visit(this)(node.program) ?? undefined) : undefined; if (program) assertIsNode(program, 'programLinkNode'); return instructionLinkNode(node.name, program); }; } if (keys.includes('instructionAccountLinkNode')) { visitor.visitInstructionAccountLink = function visitInstructionAccountLink(node) { const instruction = node.instruction ? (visit(this)(node.instruction) ?? undefined) : undefined; if (instruction) assertIsNode(instruction, 'instructionLinkNode'); return instructionAccountLinkNode(node.name, instruction); }; } if (keys.includes('instructionArgumentLinkNode')) { visitor.visitInstructionArgumentLink = function visitInstructionArgumentLink(node) { const instruction = node.instruction ? (visit(this)(node.instruction) ?? undefined) : undefined; if (instruction) assertIsNode(instruction, 'instructionLinkNode'); return instructionArgumentLinkNode(node.name, instruction); }; } if (keys.includes('pdaLinkNode')) { visitor.visitPdaLink = function visitPdaLink(node) { const program = node.program ? (visit(this)(node.program) ?? undefined) : undefined; if (program) assertIsNode(program, 'programLinkNode'); return pdaLinkNode(node.name, program); }; } return visitor as Visitor; } ================================================ FILE: packages/visitors-core/src/index.ts ================================================ export * from './bottomUpTransformerVisitor'; export * from './consoleLogVisitor'; export * from './deleteNodesVisitor'; export * from './extendVisitor'; export * from './getByteSizeVisitor'; export * from './getDebugStringVisitor'; export * from './getMaxByteSizeVisitor'; export * from './getResolvedInstructionInputsVisitor'; export * from './getUniqueHashStringVisitor'; export * from './identityVisitor'; export * from './interceptFirstVisitVisitor'; export * from './interceptVisitor'; export * from './LinkableDictionary'; export * from './mapVisitor'; export * from './mergeVisitor'; export * from './NodePath'; export * from './NodeSelector'; export * from './NodeStack'; export * from './nonNullableIdentityVisitor'; export * from './pipe'; export * from './recordLinkablesVisitor'; export * from './recordNodeStackVisitor'; export * from './removeDocsVisitor'; export * from './singleNodeVisitor'; export * from './staticVisitor'; export * from './tapVisitor'; export * from './topDownTransformerVisitor'; export * from './visitor'; export * from './voidVisitor'; ================================================ FILE: packages/visitors-core/src/interceptFirstVisitVisitor.ts ================================================ import type { NodeKind } from '@codama/nodes'; import { interceptVisitor, VisitorInterceptor } from './interceptVisitor'; import { Visitor } from './visitor'; export function interceptFirstVisitVisitor( visitor: Visitor, interceptor: VisitorInterceptor, ): Visitor { let isFirstVisit = true; return interceptVisitor(visitor, (node, next) => { try { if (isFirstVisit) { isFirstVisit = false; const result = interceptor(node, next); isFirstVisit = true; return result; } return next(node); } catch (error) { isFirstVisit = true; throw error; } }); } ================================================ FILE: packages/visitors-core/src/interceptVisitor.ts ================================================ import { Node, NodeKind, REGISTERED_NODE_KINDS } from '@codama/nodes'; import { getVisitFunctionName, GetVisitorFunctionName, Visitor } from './visitor'; export type VisitorInterceptor = (node: TNode, next: (node: TNode) => TReturn) => TReturn; export function interceptVisitor( visitor: Visitor, interceptor: VisitorInterceptor, ): Visitor { const registeredVisitFunctions = REGISTERED_NODE_KINDS.map(getVisitFunctionName); return Object.fromEntries( Object.keys(visitor).flatMap(key => { const castedKey = key as GetVisitorFunctionName; if (!registeredVisitFunctions.includes(castedKey)) { return []; } return [ [ castedKey, function interceptedVisitNode(this: Visitor, node: TNode) { const baseFunction = visitor[castedKey] as (node: TNode) => TReturn; return interceptor(node, baseFunction.bind(this)); }, ], ]; }), ) as Visitor; } ================================================ FILE: packages/visitors-core/src/mapVisitor.ts ================================================ import { GetNodeFromKind, NodeKind, REGISTERED_NODE_KINDS } from '@codama/nodes'; import { getVisitFunctionName, GetVisitorFunctionName, Visitor } from './visitor'; export function mapVisitor( visitor: Visitor, map: (from: TReturnFrom) => TReturnTo, ): Visitor { const registeredVisitFunctions = REGISTERED_NODE_KINDS.map(getVisitFunctionName); return Object.fromEntries( Object.keys(visitor).flatMap(key => { const castedKey = key as GetVisitorFunctionName; if (!registeredVisitFunctions.includes(castedKey)) { return []; } return [ [ castedKey, (node: GetNodeFromKind) => map((visitor[castedKey] as (node: GetNodeFromKind) => TReturnFrom)(node)), ], ]; }), ) as unknown as Visitor; } ================================================ FILE: packages/visitors-core/src/mergeVisitor.ts ================================================ import { getAllPrograms, Node, NodeKind, REGISTERED_NODE_KINDS } from '@codama/nodes'; import { staticVisitor } from './staticVisitor'; import { visit as baseVisit, Visitor } from './visitor'; export function mergeVisitor( leafValue: (node: Node) => TReturn, merge: (node: Node, values: TReturn[]) => TReturn, options: { keys?: TNodeKind[] } = {}, ): Visitor { const keys: NodeKind[] = options.keys ?? REGISTERED_NODE_KINDS; const visitor = staticVisitor(leafValue, { keys }) as Visitor; const visit = (v: Visitor) => (node: Node): TReturn[] => keys.includes(node.kind) ? [baseVisit(node, v)] : []; if (keys.includes('rootNode')) { visitor.visitRoot = function visitRoot(node) { return merge(node, getAllPrograms(node).flatMap(visit(this))); }; } if (keys.includes('programNode')) { visitor.visitProgram = function visitProgram(node) { return merge(node, [ ...node.pdas.flatMap(visit(this)), ...node.accounts.flatMap(visit(this)), ...(node.events ?? []).flatMap(visit(this)), ...node.instructions.flatMap(visit(this)), ...node.definedTypes.flatMap(visit(this)), ...node.errors.flatMap(visit(this)), ]); }; } if (keys.includes('pdaNode')) { visitor.visitPda = function visitPda(node) { return merge(node, node.seeds.flatMap(visit(this))); }; } if (keys.includes('accountNode')) { visitor.visitAccount = function visitAccount(node) { return merge(node, [ ...visit(this)(node.data), ...(node.pda ? visit(this)(node.pda) : []), ...(node.discriminators ?? []).flatMap(visit(this)), ]); }; } if (keys.includes('eventNode')) { visitor.visitEvent = function visitEvent(node) { return merge(node, [...visit(this)(node.data), ...(node.discriminators ?? []).flatMap(visit(this))]); }; } if (keys.includes('instructionNode')) { visitor.visitInstruction = function visitInstruction(node) { return merge(node, [ ...(node.status ? visit(this)(node.status) : []), ...node.accounts.flatMap(visit(this)), ...node.arguments.flatMap(visit(this)), ...(node.extraArguments ?? []).flatMap(visit(this)), ...(node.remainingAccounts ?? []).flatMap(visit(this)), ...(node.byteDeltas ?? []).flatMap(visit(this)), ...(node.discriminators ?? []).flatMap(visit(this)), ...(node.subInstructions ?? []).flatMap(visit(this)), ]); }; } if (keys.includes('instructionAccountNode')) { visitor.visitInstructionAccount = function visitInstructionAccount(node) { return merge(node, [...(node.defaultValue ? visit(this)(node.defaultValue) : [])]); }; } if (keys.includes('instructionArgumentNode')) { visitor.visitInstructionArgument = function visitInstructionArgument(node) { return merge(node, [ ...visit(this)(node.type), ...(node.defaultValue ? visit(this)(node.defaultValue) : []), ]); }; } if (keys.includes('instructionRemainingAccountsNode')) { visitor.visitInstructionRemainingAccounts = function visitInstructionRemainingAccounts(node) { return merge(node, visit(this)(node.value)); }; } if (keys.includes('instructionByteDeltaNode')) { visitor.visitInstructionByteDelta = function visitInstructionByteDelta(node) { return merge(node, visit(this)(node.value)); }; } if (keys.includes('instructionStatusNode')) { visitor.visitInstructionStatus = function visitInstructionStatus(node) { return merge(node, []); }; } if (keys.includes('definedTypeNode')) { visitor.visitDefinedType = function visitDefinedType(node) { return merge(node, visit(this)(node.type)); }; } if (keys.includes('arrayTypeNode')) { visitor.visitArrayType = function visitArrayType(node) { return merge(node, [...visit(this)(node.count), ...visit(this)(node.item)]); }; } if (keys.includes('enumTypeNode')) { visitor.visitEnumType = function visitEnumType(node) { return merge(node, [...visit(this)(node.size), ...node.variants.flatMap(visit(this))]); }; } if (keys.includes('enumStructVariantTypeNode')) { visitor.visitEnumStructVariantType = function visitEnumStructVariantType(node) { return merge(node, visit(this)(node.struct)); }; } if (keys.includes('enumTupleVariantTypeNode')) { visitor.visitEnumTupleVariantType = function visitEnumTupleVariantType(node) { return merge(node, visit(this)(node.tuple)); }; } if (keys.includes('mapTypeNode')) { visitor.visitMapType = function visitMapType(node) { return merge(node, [...visit(this)(node.count), ...visit(this)(node.key), ...visit(this)(node.value)]); }; } if (keys.includes('optionTypeNode')) { visitor.visitOptionType = function visitOptionType(node) { return merge(node, [...visit(this)(node.prefix), ...visit(this)(node.item)]); }; } if (keys.includes('zeroableOptionTypeNode')) { visitor.visitZeroableOptionType = function visitZeroableOptionType(node) { return merge(node, [...visit(this)(node.item), ...(node.zeroValue ? visit(this)(node.zeroValue) : [])]); }; } if (keys.includes('remainderOptionTypeNode')) { visitor.visitRemainderOptionType = function visitRemainderOptionType(node) { return merge(node, visit(this)(node.item)); }; } if (keys.includes('booleanTypeNode')) { visitor.visitBooleanType = function visitBooleanType(node) { return merge(node, visit(this)(node.size)); }; } if (keys.includes('setTypeNode')) { visitor.visitSetType = function visitSetType(node) { return merge(node, [...visit(this)(node.count), ...visit(this)(node.item)]); }; } if (keys.includes('structTypeNode')) { visitor.visitStructType = function visitStructType(node) { return merge(node, node.fields.flatMap(visit(this))); }; } if (keys.includes('structFieldTypeNode')) { visitor.visitStructFieldType = function visitStructFieldType(node) { return merge(node, [ ...visit(this)(node.type), ...(node.defaultValue ? visit(this)(node.defaultValue) : []), ]); }; } if (keys.includes('tupleTypeNode')) { visitor.visitTupleType = function visitTupleType(node) { return merge(node, node.items.flatMap(visit(this))); }; } if (keys.includes('amountTypeNode')) { visitor.visitAmountType = function visitAmountType(node) { return merge(node, visit(this)(node.number)); }; } if (keys.includes('dateTimeTypeNode')) { visitor.visitDateTimeType = function visitDateTimeType(node) { return merge(node, visit(this)(node.number)); }; } if (keys.includes('solAmountTypeNode')) { visitor.visitSolAmountType = function visitSolAmountType(node) { return merge(node, visit(this)(node.number)); }; } if (keys.includes('prefixedCountNode')) { visitor.visitPrefixedCount = function visitPrefixedCount(node) { return merge(node, visit(this)(node.prefix)); }; } if (keys.includes('arrayValueNode')) { visitor.visitArrayValue = function visitArrayValue(node) { return merge(node, node.items.flatMap(visit(this))); }; } if (keys.includes('constantValueNode')) { visitor.visitConstantValue = function visitConstantValue(node) { return merge(node, [...visit(this)(node.type), ...visit(this)(node.value)]); }; } if (keys.includes('enumValueNode')) { visitor.visitEnumValue = function visitEnumValue(node) { return merge(node, [...visit(this)(node.enum), ...(node.value ? visit(this)(node.value) : [])]); }; } if (keys.includes('mapValueNode')) { visitor.visitMapValue = function visitMapValue(node) { return merge(node, node.entries.flatMap(visit(this))); }; } if (keys.includes('mapEntryValueNode')) { visitor.visitMapEntryValue = function visitMapEntryValue(node) { return merge(node, [...visit(this)(node.key), ...visit(this)(node.value)]); }; } if (keys.includes('setValueNode')) { visitor.visitSetValue = function visitSetValue(node) { return merge(node, node.items.flatMap(visit(this))); }; } if (keys.includes('someValueNode')) { visitor.visitSomeValue = function visitSomeValue(node) { return merge(node, visit(this)(node.value)); }; } if (keys.includes('structValueNode')) { visitor.visitStructValue = function visitStructValue(node) { return merge(node, node.fields.flatMap(visit(this))); }; } if (keys.includes('structFieldValueNode')) { visitor.visitStructFieldValue = function visitStructFieldValue(node) { return merge(node, visit(this)(node.value)); }; } if (keys.includes('tupleValueNode')) { visitor.visitTupleValue = function visitTupleValue(node) { return merge(node, node.items.flatMap(visit(this))); }; } if (keys.includes('constantPdaSeedNode')) { visitor.visitConstantPdaSeed = function visitConstantPdaSeed(node) { return merge(node, [...visit(this)(node.type), ...visit(this)(node.value)]); }; } if (keys.includes('variablePdaSeedNode')) { visitor.visitVariablePdaSeed = function visitVariablePdaSeed(node) { return merge(node, visit(this)(node.type)); }; } if (keys.includes('resolverValueNode')) { visitor.visitResolverValue = function visitResolverValue(node) { return merge(node, (node.dependsOn ?? []).flatMap(visit(this))); }; } if (keys.includes('conditionalValueNode')) { visitor.visitConditionalValue = function visitConditionalValue(node) { return merge(node, [ ...visit(this)(node.condition), ...(node.value ? visit(this)(node.value) : []), ...(node.ifTrue ? visit(this)(node.ifTrue) : []), ...(node.ifFalse ? visit(this)(node.ifFalse) : []), ]); }; } if (keys.includes('pdaValueNode')) { visitor.visitPdaValue = function visitPdaValue(node) { return merge(node, [...visit(this)(node.pda), ...node.seeds.flatMap(visit(this))]); }; } if (keys.includes('pdaSeedValueNode')) { visitor.visitPdaSeedValue = function visitPdaSeedValue(node) { return merge(node, visit(this)(node.value)); }; } if (keys.includes('fixedSizeTypeNode')) { visitor.visitFixedSizeType = function visitFixedSizeType(node) { return merge(node, visit(this)(node.type)); }; } if (keys.includes('sizePrefixTypeNode')) { visitor.visitSizePrefixType = function visitSizePrefixType(node) { return merge(node, [...visit(this)(node.prefix), ...visit(this)(node.type)]); }; } if (keys.includes('preOffsetTypeNode')) { visitor.visitPreOffsetType = function visitPreOffsetType(node) { return merge(node, visit(this)(node.type)); }; } if (keys.includes('postOffsetTypeNode')) { visitor.visitPostOffsetType = function visitPostOffsetType(node) { return merge(node, visit(this)(node.type)); }; } if (keys.includes('sentinelTypeNode')) { visitor.visitSentinelType = function visitSentinelType(node) { return merge(node, [...visit(this)(node.sentinel), ...visit(this)(node.type)]); }; } if (keys.includes('hiddenPrefixTypeNode')) { visitor.visitHiddenPrefixType = function visitHiddenPrefixType(node) { return merge(node, [...node.prefix.flatMap(visit(this)), ...visit(this)(node.type)]); }; } if (keys.includes('hiddenSuffixTypeNode')) { visitor.visitHiddenSuffixType = function visitHiddenSuffixType(node) { return merge(node, [...visit(this)(node.type), ...node.suffix.flatMap(visit(this))]); }; } if (keys.includes('constantDiscriminatorNode')) { visitor.visitConstantDiscriminator = function visitConstantDiscriminator(node) { return merge(node, visit(this)(node.constant)); }; } if (keys.includes('accountLinkNode')) { visitor.visitAccountLink = function visitAccountLink(node) { return merge(node, node.program ? visit(this)(node.program) : []); }; } if (keys.includes('definedTypeLinkNode')) { visitor.visitDefinedTypeLink = function visitDefinedTypeLink(node) { return merge(node, node.program ? visit(this)(node.program) : []); }; } if (keys.includes('instructionLinkNode')) { visitor.visitInstructionLink = function visitInstructionLink(node) { return merge(node, node.program ? visit(this)(node.program) : []); }; } if (keys.includes('instructionAccountLinkNode')) { visitor.visitInstructionAccountLink = function visitInstructionAccountLink(node) { return merge(node, node.instruction ? visit(this)(node.instruction) : []); }; } if (keys.includes('instructionArgumentLinkNode')) { visitor.visitInstructionArgumentLink = function visitInstructionArgumentLink(node) { return merge(node, node.instruction ? visit(this)(node.instruction) : []); }; } if (keys.includes('pdaLinkNode')) { visitor.visitPdaLink = function visitPdaLink(node) { return merge(node, node.program ? visit(this)(node.program) : []); }; } return visitor as Visitor; } ================================================ FILE: packages/visitors-core/src/nonNullableIdentityVisitor.ts ================================================ import { Node, NodeKind } from '@codama/nodes'; import { identityVisitor } from './identityVisitor'; import { Visitor } from './visitor'; export function nonNullableIdentityVisitor( options: { keys?: TNodeKind[] } = {}, ): Visitor { return identityVisitor(options) as Visitor; } ================================================ FILE: packages/visitors-core/src/pipe.ts ================================================ /** * Copied from @solana/functional. * @see https://github.com/anza-xyz/kit/blob/main/packages/functional/src/pipe.ts * * --- * * General pipe function. * Provide an initial value and a list of functions to pipe it through. * * Following common implementations of pipe functions that use TypeScript, * this function supports a maximum arity of 10 for type safety. * @see https://github.com/ramda/ramda/blob/master/source/pipe.js * @see https://github.com/darky/rocket-pipes/blob/master/index.ts * * Note you can use nested pipes to extend this limitation, like so: * ```typescript * const myValue = pipe( * pipe( * 1, * (x) => x + 1, * (x) => x * 2, * (x) => x - 1, * ), * (y) => y / 3, * (y) => y + 1, * ); * ``` * @param init The initial value * @param fns Any number of functions to pipe the value through * @returns The final value with all functions applied */ export function pipe(init: TInitial): TInitial; export function pipe(init: TInitial, init_r1: (init: TInitial) => R1): R1; export function pipe(init: TInitial, init_r1: (init: TInitial) => R1, r1_r2: (r1: R1) => R2): R2; export function pipe( init: TInitial, init_r1: (init: TInitial) => R1, r1_r2: (r1: R1) => R2, r2_r3: (r2: R2) => R3, ): R3; export function pipe( init: TInitial, init_r1: (init: TInitial) => R1, r1_r2: (r1: R1) => R2, r2_r3: (r2: R2) => R3, r3_r4: (r3: R3) => R4, ): R4; export function pipe( init: TInitial, init_r1: (init: TInitial) => R1, r1_r2: (r1: R1) => R2, r2_r3: (r2: R2) => R3, r3_r4: (r3: R3) => R4, r4_r5: (r4: R4) => R5, ): R5; export function pipe( init: TInitial, init_r1: (init: TInitial) => R1, r1_r2: (r1: R1) => R2, r2_r3: (r2: R2) => R3, r3_r4: (r3: R3) => R4, r4_r5: (r4: R4) => R5, r5_r6: (r5: R5) => R6, ): R6; export function pipe( init: TInitial, init_r1: (init: TInitial) => R1, r1_r2: (r1: R1) => R2, r2_r3: (r2: R2) => R3, r3_r4: (r3: R3) => R4, r4_r5: (r4: R4) => R5, r5_r6: (r5: R5) => R6, r6_r7: (r6: R6) => R7, ): R7; export function pipe( init: TInitial, init_r1: (init: TInitial) => R1, r1_r2: (r1: R1) => R2, r2_r3: (r2: R2) => R3, r3_r4: (r3: R3) => R4, r4_r5: (r4: R4) => R5, r5_r6: (r5: R5) => R6, r6_r7: (r6: R6) => R7, r7_r8: (r7: R7) => R8, ): R8; export function pipe( init: TInitial, init_r1: (init: TInitial) => R1, r1_r2: (r1: R1) => R2, r2_r3: (r2: R2) => R3, r3_r4: (r3: R3) => R4, r4_r5: (r4: R4) => R5, r5_r6: (r5: R5) => R6, r6_r7: (r6: R6) => R7, r7_r8: (r7: R7) => R8, r8_r9: (r8: R8) => R9, ): R9; export function pipe( init: TInitial, init_r1: (init: TInitial) => R1, r1_r2: (r1: R1) => R2, r2_r3: (r2: R2) => R3, r3_r4: (r3: R3) => R4, r4_r5: (r4: R4) => R5, r5_r6: (r5: R5) => R6, r6_r7: (r6: R6) => R7, r7_r8: (r7: R7) => R8, r8_r9: (r8: R8) => R9, r9_r10: (r9: R9) => R10, ): R10; export function pipe(init: TInitial, ...fns: CallableFunction[]) { // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call return fns.reduce((acc, fn) => fn(acc), init); } ================================================ FILE: packages/visitors-core/src/recordLinkablesVisitor.ts ================================================ import { isNode, type NodeKind } from '@codama/nodes'; import { interceptFirstVisitVisitor } from './interceptFirstVisitVisitor'; import { interceptVisitor } from './interceptVisitor'; import { LINKABLE_NODES, LinkableDictionary } from './LinkableDictionary'; import { NodeStack } from './NodeStack'; import { pipe } from './pipe'; import { recordNodeStackVisitor } from './recordNodeStackVisitor'; import { visit, Visitor } from './visitor'; import { voidVisitor } from './voidVisitor'; export function getRecordLinkablesVisitor( linkables: LinkableDictionary, ): Visitor { const stack = new NodeStack(); return pipe( voidVisitor(), v => interceptVisitor(v, (node, next) => { if (isNode(node, LINKABLE_NODES)) { linkables.recordPath(stack.getPath(LINKABLE_NODES)); } return next(node); }), v => recordNodeStackVisitor(v, stack), ); } export function recordLinkablesOnFirstVisitVisitor( visitor: Visitor, linkables: LinkableDictionary, ): Visitor { const recordingVisitor = getRecordLinkablesVisitor(linkables); return pipe(visitor, v => interceptFirstVisitVisitor(v, (node, next) => { visit(node, recordingVisitor); return next(node); }), ); } ================================================ FILE: packages/visitors-core/src/recordNodeStackVisitor.ts ================================================ import { NodeKind } from '@codama/nodes'; import { interceptVisitor } from './interceptVisitor'; import { NodeStack } from './NodeStack'; import { Visitor } from './visitor'; export function recordNodeStackVisitor( visitor: Visitor, stack: NodeStack, ): Visitor { return interceptVisitor(visitor, (node, next) => { stack.push(node); const newNode = next(node); stack.pop(); return newNode; }); } ================================================ FILE: packages/visitors-core/src/removeDocsVisitor.ts ================================================ import { NodeKind } from '@codama/nodes'; import { interceptVisitor } from './interceptVisitor'; import { nonNullableIdentityVisitor } from './nonNullableIdentityVisitor'; export function removeDocsVisitor(options: { keys?: TNodeKind[] } = {}) { return interceptVisitor(nonNullableIdentityVisitor(options), (node, next) => { if ('docs' in node) { return next({ ...node, docs: [] }); } return next(node); }); } ================================================ FILE: packages/visitors-core/src/singleNodeVisitor.ts ================================================ import { GetNodeFromKind, NodeKind, RootNode } from '@codama/nodes'; import { getVisitFunctionName, GetVisitorFunctionName, Visitor } from './visitor'; export function singleNodeVisitor( key: TNodeKey, fn: (node: GetNodeFromKind) => TReturn, ): Visitor { const visitor = {} as Visitor; visitor[getVisitFunctionName(key)] = fn as unknown as Visitor[GetVisitorFunctionName]; return visitor; } export function rootNodeVisitor(fn: (node: RootNode) => TReturn) { return singleNodeVisitor('rootNode', fn); } ================================================ FILE: packages/visitors-core/src/staticVisitor.ts ================================================ import { Node, NodeKind, REGISTERED_NODE_KINDS } from '@codama/nodes'; import { getVisitFunctionName, Visitor } from './visitor'; export function staticVisitor( fn: (node: Node) => TReturn, options: { keys?: TNodeKind[] } = {}, ): Visitor { const keys = options.keys ?? (REGISTERED_NODE_KINDS as TNodeKind[]); const visitor = {} as Visitor; keys.forEach(key => { visitor[getVisitFunctionName(key)] = fn.bind(visitor); }); return visitor; } ================================================ FILE: packages/visitors-core/src/tapVisitor.ts ================================================ import { GetNodeFromKind, NodeKind } from '@codama/nodes'; import { getVisitFunctionName, GetVisitorFunctionName, Visitor } from './visitor'; export function tapVisitor>( visitor: TVisitor, key: TNodeKey, tap: (node: GetNodeFromKind) => void, ): TVisitor { const newVisitor = { ...visitor }; newVisitor[getVisitFunctionName(key)] = function tappedVisitNode( this: TVisitor, node: GetNodeFromKind, ): TReturn { tap(node); const parentFunction = visitor[getVisitFunctionName(key)] as (node: GetNodeFromKind) => TReturn; return parentFunction.bind(this)(node); } as TVisitor[GetVisitorFunctionName]; return newVisitor; } ================================================ FILE: packages/visitors-core/src/topDownTransformerVisitor.ts ================================================ import { Node, NodeKind, REGISTERED_NODE_KINDS } from '@codama/nodes'; import { identityVisitor } from './identityVisitor'; import { interceptVisitor } from './interceptVisitor'; import { getConjunctiveNodeSelectorFunction, NodeSelector } from './NodeSelector'; import { NodeStack } from './NodeStack'; import { pipe } from './pipe'; import { recordNodeStackVisitor } from './recordNodeStackVisitor'; import { Visitor } from './visitor'; export type TopDownNodeTransformer = (node: TNode, stack: NodeStack) => TNode | null; export type TopDownNodeTransformerWithSelector = { select: NodeSelector | NodeSelector[]; transform: TopDownNodeTransformer; }; export function topDownTransformerVisitor( transformers: (TopDownNodeTransformer | TopDownNodeTransformerWithSelector)[], options: { keys?: TNodeKind[]; stack?: NodeStack } = {}, ): Visitor { const transformerFunctions = transformers.map((transformer): TopDownNodeTransformer => { if (typeof transformer === 'function') return transformer; return (node, stack) => getConjunctiveNodeSelectorFunction(transformer.select)(stack.getPath(REGISTERED_NODE_KINDS)) ? transformer.transform(node, stack) : node; }); const stack = options.stack ?? new NodeStack(); return pipe( identityVisitor(options), v => interceptVisitor(v, (node, next) => { const appliedNode = transformerFunctions.reduce( (acc, transformer) => (acc === null ? null : transformer(acc, stack)), node as Parameters[0] | null, ); if (appliedNode === null) return null; return next(appliedNode); }), v => recordNodeStackVisitor(v, stack), ); } ================================================ FILE: packages/visitors-core/src/visitor.ts ================================================ import { CODAMA_ERROR__UNRECOGNIZED_NODE_KIND, CodamaError } from '@codama/errors'; import { type GetNodeFromKind, type Node, type NodeKind, pascalCase, REGISTERED_NODE_KINDS } from '@codama/nodes'; export type Visitor = { [K in TNodeKind as GetVisitorFunctionName]: (node: GetNodeFromKind) => TReturn; }; export type GetVisitorFunctionName = T extends `${infer TWithoutNode}Node` ? `visit${Capitalize}` : never; export function visit(node: TNode, visitor: Visitor): TReturn { const key = getVisitFunctionName(node.kind) as GetVisitorFunctionName; return (visitor[key] as (typeof visitor)[typeof key] & ((node: TNode) => TReturn))(node); } export function visitOrElse( node: TNode, visitor: Visitor, fallback: (node: TNode) => TReturn, ): TReturn { const key = getVisitFunctionName(node.kind); return (key in visitor ? (visitor[key] as (node: TNode) => TReturn) : fallback)(node); } export function getVisitFunctionName(nodeKind: TNodeKind) { if (!REGISTERED_NODE_KINDS.includes(nodeKind)) { throw new CodamaError(CODAMA_ERROR__UNRECOGNIZED_NODE_KIND, { kind: nodeKind }); } return `visit${pascalCase(nodeKind.slice(0, -4))}` as GetVisitorFunctionName; } ================================================ FILE: packages/visitors-core/src/voidVisitor.ts ================================================ import type { NodeKind } from '@codama/nodes'; import { mergeVisitor } from './mergeVisitor'; import { Visitor } from './visitor'; export function voidVisitor( options: { keys?: TNodeKind[] } = {}, ): Visitor { return mergeVisitor( () => undefined, () => undefined, options, ); } ================================================ FILE: packages/visitors-core/test/NodeSelector.test.ts ================================================ import { accountNode, booleanTypeNode, definedTypeLinkNode, definedTypeNode, enumEmptyVariantTypeNode, enumStructVariantTypeNode, enumTypeNode, errorNode, instructionAccountNode, instructionArgumentNode, instructionNode, Node, numberTypeNode, optionTypeNode, programNode, publicKeyTypeNode, rootNode, structFieldTypeNode, structTypeNode, } from '@codama/nodes'; import { expect, test } from 'vitest'; import { getLastNodeFromPath, getNodeSelectorFunction, identityVisitor, interceptVisitor, isNodePath, NodePath, NodeSelector, NodeStack, pipe, recordNodeStackVisitor, visit, } from '../src'; // Given the following tree. const tree = rootNode( programNode({ accounts: [ accountNode({ data: structTypeNode([ structFieldTypeNode({ name: 'owner', type: publicKeyTypeNode(), }), structFieldTypeNode({ name: 'mint', type: publicKeyTypeNode(), }), structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64'), }), structFieldTypeNode({ name: 'delegatedAmount', type: optionTypeNode(numberTypeNode('u64'), { prefix: numberTypeNode('u32'), }), }), ]), name: 'token', }), ], definedTypes: [], errors: [ errorNode({ code: 0, message: 'Invalid program ID', name: 'invalidProgramId', }), errorNode({ code: 1, message: 'Invalid token owner', name: 'invalidTokenOwner', }), ], instructions: [ instructionNode({ accounts: [ instructionAccountNode({ isSigner: false, isWritable: true, name: 'token', }), instructionAccountNode({ isSigner: false, isWritable: true, name: 'mint', }), instructionAccountNode({ isSigner: true, isWritable: false, name: 'mintAuthority', }), ], arguments: [ instructionArgumentNode({ name: 'amount', type: numberTypeNode('u64'), }), ], name: 'mintToken', }), ], name: 'splToken', publicKey: '1111', version: '1.0.0', }), [ programNode({ accounts: [ accountNode({ data: structTypeNode([ structFieldTypeNode({ name: 'owner', type: publicKeyTypeNode(), }), structFieldTypeNode({ name: 'opened', type: booleanTypeNode(numberTypeNode('u64')), }), structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64'), }), structFieldTypeNode({ name: 'wrappingPaper', type: definedTypeLinkNode('wrappingPaper'), }), ]), name: 'gift', }), ], definedTypes: [ definedTypeNode({ name: 'wrappingPaper', type: enumTypeNode([ enumEmptyVariantTypeNode('blue'), enumEmptyVariantTypeNode('red'), enumStructVariantTypeNode( 'gold', structTypeNode([ structFieldTypeNode({ name: 'owner', type: publicKeyTypeNode(), }), ]), ), ]), }), ], errors: [ errorNode({ code: 0, message: 'Invalid program ID', name: 'invalidProgramId', }), ], instructions: [ instructionNode({ accounts: [ instructionAccountNode({ isSigner: false, isWritable: true, name: 'gift', }), instructionAccountNode({ isSigner: true, isWritable: false, name: 'owner', }), ], arguments: [], name: 'openGift', }), ], name: 'christmasProgram', publicKey: '2222', version: '1.0.0', }), ], ); const macro = (selector: NodeSelector, expectedSelected: Node[]) => { const title = typeof selector === 'string' ? `it can select nodes using paths: "${selector}"` : 'it can select nodes using functions'; test(title, () => { // Given a selector function created from the selector. const selectorFunction = getNodeSelectorFunction(selector); // And given a visitor that keeps track of selected nodes. const stack = new NodeStack(); const selected = [] as Node[]; const visitor = pipe( identityVisitor(), v => interceptVisitor(v, (node, next) => { if (selectorFunction(stack.getPath() as NodePath)) selected.push(node); return next(node); }), v => recordNodeStackVisitor(v, stack), ); // When we visit the tree. visit(tree, visitor); // Then the selected nodes are as expected. expect(expectedSelected).toEqual(selected); selected.forEach((node, index) => expect(node).toBe(expectedSelected[index])); }); }; /** * [programNode] splToken * [accountNode] token > [structTypeNode] * [structFieldTypeNode] owner > [publicKeyTypeNode] * [structFieldTypeNode] mint > [publicKeyTypeNode] * [structFieldTypeNode] amount > [numberTypeNode] (u64) * [structFieldTypeNode] delegatedAmount > [optionTypeNode] (prefix: [numberTypeNode] (u32)) > [numberTypeNode] (u64) * [instructionNode] mintToken * [instructionAccountNode] token * [instructionAccountNode] mint * [instructionAccountNode] mintAuthority * [instructionArgumentNode] amount * [numberTypeNode] (u64) * [errorNode] invalidProgramId (0) * [errorNode] invalidTokenOwner (1) * [programNode] christmasProgram * [accountNode] gift > [structTypeNode] * [structFieldTypeNode] owner > [publicKeyTypeNode] * [structFieldTypeNode] opened > [booleanTypeNode] > [numberTypeNode] (u64) * [structFieldTypeNode] amount > [numberTypeNode] (u64) * [structFieldTypeNode] wrappingPaper > [definedTypeLinkNode] wrappingPaper * [instructionNode] openGift * [instructionAccountNode] gift * [instructionAccountNode] owner * [definedTypeNode] wrappingPaper > [enumTypeNode] * [enumEmptyVariantTypeNode] blue * [enumEmptyVariantTypeNode] red * [enumStructVariantTypeNode] gold > [structTypeNode] * [structFieldTypeNode] owner > [publicKeyTypeNode] * [errorNode] invalidProgramId (0) */ const splTokenProgram = tree.program; const christmasProgram = tree.additionalPrograms[0]; const tokenAccount = splTokenProgram.accounts[0]; const tokenDelegatedAmountOption = tokenAccount.data.fields[3].type; const mintTokenInstruction = splTokenProgram.instructions[0]; const giftAccount = christmasProgram.accounts[0]; const openGiftInstruction = christmasProgram.instructions[0]; const wrappingPaper = christmasProgram.definedTypes[0]; const wrappingPaperEnum = wrappingPaper.type; const wrappingPaperEnumGold = wrappingPaperEnum.variants[2]; // Select programs. macro('[programNode]', [splTokenProgram, christmasProgram]); macro('[programNode]splToken', [splTokenProgram]); macro('christmasProgram', [christmasProgram]); // Select and filter owner nodes. macro('owner', [ tokenAccount.data.fields[0], giftAccount.data.fields[0], wrappingPaperEnumGold.struct.fields[0], openGiftInstruction.accounts[1], ]); macro('[structFieldTypeNode]owner', [ tokenAccount.data.fields[0], giftAccount.data.fields[0], wrappingPaperEnumGold.struct.fields[0], ]); macro('splToken.owner', [tokenAccount.data.fields[0]]); macro('[instructionNode].owner', [openGiftInstruction.accounts[1]]); macro('[accountNode].owner', [tokenAccount.data.fields[0], giftAccount.data.fields[0]]); macro('[accountNode]token.owner', [tokenAccount.data.fields[0]]); macro('christmasProgram.[accountNode].owner', [giftAccount.data.fields[0]]); macro('[programNode]christmasProgram.[definedTypeNode]wrappingPaper.[enumStructVariantTypeNode]gold.owner', [ wrappingPaperEnumGold.struct.fields[0], ]); macro('christmasProgram.wrappingPaper.gold.owner', [wrappingPaperEnumGold.struct.fields[0]]); // Select all descendants of a node. macro('wrappingPaper.*', [ giftAccount.data.fields[3].type, wrappingPaperEnum, wrappingPaperEnum.variants[0], wrappingPaperEnum.variants[1], wrappingPaperEnum.variants[2], wrappingPaperEnumGold.struct, wrappingPaperEnumGold.struct.fields[0], wrappingPaperEnumGold.struct.fields[0].type, ]); macro('wrappingPaper.[structFieldTypeNode]', [wrappingPaperEnumGold.struct.fields[0]]); macro('wrappingPaper.blue', [wrappingPaperEnum.variants[0]]); macro('amount.*', [ tokenAccount.data.fields[2].type, mintTokenInstruction.arguments[0].type, giftAccount.data.fields[2].type, ]); macro('[instructionNode].amount.*', [mintTokenInstruction.arguments[0].type]); macro('[structFieldTypeNode].*', [ tokenAccount.data.fields[0].type, tokenAccount.data.fields[1].type, tokenAccount.data.fields[2].type, tokenAccount.data.fields[3].type, tokenDelegatedAmountOption.prefix, tokenDelegatedAmountOption.item, giftAccount.data.fields[0].type, giftAccount.data.fields[1].type, giftAccount.data.fields[1].type.size, giftAccount.data.fields[2].type, giftAccount.data.fields[3].type, wrappingPaperEnumGold.struct.fields[0].type, ]); macro('[structFieldTypeNode].*.*', [ tokenDelegatedAmountOption.prefix, tokenDelegatedAmountOption.item, giftAccount.data.fields[1].type.size, ]); // Select multiple node kinds. macro('[accountNode]gift.[publicKeyTypeNode|booleanTypeNode]', [ giftAccount.data.fields[0].type, giftAccount.data.fields[1].type, ]); // Select using functions. macro( path => isNodePath(path, 'numberTypeNode') && getLastNodeFromPath(path).format === 'u32', [tokenDelegatedAmountOption.prefix], ); ================================================ FILE: packages/visitors-core/test/bottomUpTransformerVisitor.test.ts ================================================ import { definedTypeNode, isNode, numberTypeNode, programNode, publicKeyTypeNode, stringTypeNode, tupleTypeNode, TYPE_NODES, } from '@codama/nodes'; import { expect, test } from 'vitest'; import { BottomUpNodeTransformerWithSelector, bottomUpTransformerVisitor, findProgramNodeFromPath, NodeStack, visit, } from '../src'; test('it can transform nodes into other nodes', () => { // Given the following tree. const node = tupleTypeNode([numberTypeNode('u32'), tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()])]); // And a transformer visitor that transforms all number nodes into string nodes. const visitor = bottomUpTransformerVisitor([ node => (isNode(node, 'numberTypeNode') ? stringTypeNode('utf8') : node), ]); // When we visit the tree using that visitor. const result = visit(node, visitor); // Then we expect the number nodes to have been transformed into string nodes. expect(result).toEqual( tupleTypeNode([stringTypeNode('utf8'), tupleTypeNode([stringTypeNode('utf8'), publicKeyTypeNode()])]), ); }); test('it can transform nodes using node selectors', () => { // Given the following tree. const node = tupleTypeNode([numberTypeNode('u32'), tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()])]); // And a transformer visitor that selects all number nodes and transforms them into string nodes. const visitor = bottomUpTransformerVisitor([ { select: '[numberTypeNode]', transform: () => stringTypeNode('utf8'), }, ]); // When we visit the tree using that visitor. const result = visit(node, visitor); // Then we expect the number nodes to have been transformed into string nodes. expect(result).toEqual( tupleTypeNode([stringTypeNode('utf8'), tupleTypeNode([stringTypeNode('utf8'), publicKeyTypeNode()])]), ); }); test('it can create partial transformer visitors', () => { // Given the following tree. const node = tupleTypeNode([numberTypeNode('u32'), tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()])]); // And a transformer visitor that wraps every node into another tuple node // but that does not transform public key nodes. const visitor = bottomUpTransformerVisitor([node => (isNode(node, TYPE_NODES) ? tupleTypeNode([node]) : node)], { keys: ['tupleTypeNode', 'numberTypeNode'], }); // When we visit the tree using that visitor. const result = visit(node, visitor); // Then we expect the following tree. expect(result).toEqual( tupleTypeNode([ tupleTypeNode([ tupleTypeNode([numberTypeNode('u32')]), tupleTypeNode([tupleTypeNode([tupleTypeNode([numberTypeNode('u32')]), publicKeyTypeNode()])]), ]), ]), ); // And the public key node cannot be visited. // @ts-expect-error PublicKeyTypeNode is not supported. expect(() => visit(publicKeyTypeNode(), visitor)).toThrow(); }); test('it can be used to delete nodes', () => { // Given the following tree. const node = tupleTypeNode([numberTypeNode('u32'), tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()])]); // And a transformer visitor that deletes all number nodes. const visitor = bottomUpTransformerVisitor([{ select: '[numberTypeNode]', transform: () => null }]); // When we visit the tree using that visitor. const result = visit(node, visitor); // Then we expect the number nodes to have been deleted. expect(result).toEqual(tupleTypeNode([tupleTypeNode([publicKeyTypeNode()])])); }); test('it can transform nodes using multiple node selectors', () => { // Given the following tree. const node = tupleTypeNode([numberTypeNode('u32'), tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()])]); // And a transformer visitor that uses two node selectors such that // - the first one selects all number nodes, and // - the second one selects all nodes with more than one ancestor. const visitor = bottomUpTransformerVisitor([ { select: ['[numberTypeNode]', path => path.length > 2], transform: () => stringTypeNode('utf8'), }, ]); // When we visit the tree using that visitor. const result = visit(node, visitor); // Then we expect both node selectors to have been applied. expect(result).toEqual( tupleTypeNode([numberTypeNode('u32'), tupleTypeNode([stringTypeNode('utf8'), publicKeyTypeNode()])]), ); }); test('it can start from an existing stack', () => { // Given the following tuple node inside a program node. const tuple = tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()]); const program = programNode({ definedTypes: [definedTypeNode({ name: 'myTuple', type: tuple })], name: 'myProgram', publicKey: '1111', }); // And a transformer that removes all number nodes // from programs whose public key is '1111'. const transformer: BottomUpNodeTransformerWithSelector = { select: ['[numberTypeNode]', path => findProgramNodeFromPath(path)?.publicKey === '1111'], transform: () => null, }; // When we visit the tuple with an existing stack that contains the program node. const stack = new NodeStack([program, program.definedTypes[0]]); const resultWithStack = visit(tuple, bottomUpTransformerVisitor([transformer], { stack })); // Then we expect the number node to have been removed. expect(resultWithStack).toStrictEqual(tupleTypeNode([publicKeyTypeNode()])); // But when we visit the tuple without the stack. const resultWithoutStack = visit(tuple, bottomUpTransformerVisitor([transformer])); // Then we expect the number node to have been kept. expect(resultWithoutStack).toStrictEqual(tuple); }); ================================================ FILE: packages/visitors-core/test/deleteNodesVisitor.test.ts ================================================ import { numberTypeNode, publicKeyTypeNode, tupleTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { deleteNodesVisitor, visit } from '../src'; test('it can delete nodes using selectors', () => { // Given the following tree. const node = tupleTypeNode([numberTypeNode('u32'), tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()])]); // And a visitor that deletes all number nodes. const visitor = deleteNodesVisitor(['[numberTypeNode]']); // When we visit the tree using that visitor. const result = visit(node, visitor); // Then we expect the number nodes to have been deleted. expect(result).toEqual(tupleTypeNode([tupleTypeNode([publicKeyTypeNode()])])); }); test('it can create partial visitors', () => { // Given the following tree. const node = tupleTypeNode([numberTypeNode('u32'), tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()])]); // And a visitor that deletes all number nodes and public key nodes // but does not support public key nodes. const visitor = deleteNodesVisitor(['[numberTypeNode]', '[publicKeyTypeNode]'], { keys: ['tupleTypeNode', 'numberTypeNode'], }); // When we visit the tree using that visitor. const result = visit(node, visitor); // Then only the number nodes have been deleted. expect(result).toEqual(tupleTypeNode([tupleTypeNode([publicKeyTypeNode()])])); // And the public key node cannot be visited. // @ts-expect-error PublicKeyTypeNode is not supported. expect(() => visit(publicKeyTypeNode(), visitor)).toThrow(); }); ================================================ FILE: packages/visitors-core/test/extendVisitor.test.ts ================================================ import { CODAMA_ERROR__VISITORS__CANNOT_EXTEND_MISSING_VISIT_FUNCTION, CodamaError } from '@codama/errors'; import { numberTypeNode, publicKeyTypeNode, tupleTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { extendVisitor, mergeVisitor, visit, voidVisitor } from '../src'; test('it returns a new visitor that extends a subset of visits with a next function', () => { // Given the following 3-nodes tree. const node = tupleTypeNode([numberTypeNode('u32'), tupleTypeNode([numberTypeNode('u64'), publicKeyTypeNode()])]); // And an extended sum visitor that adds an extra 10 to tuple and public key nodes. const baseVisitor = mergeVisitor( () => 1, (_, values) => values.reduce((a, b) => a + b, 1), ); const visitor = extendVisitor(baseVisitor, { visitPublicKeyType: (node, { next }) => next(node) + 10, visitTupleType: (node, { next }) => next(node) + 10, }); // When we visit the tree using that visitor. const result = visit(node, visitor); // Then we expect the following count. expect(result).toBe(35); // And the extended visitor is a new instance. expect(baseVisitor).not.toBe(visitor); }); test('it can visit itself using the exposed self argument', () => { // Given the following 3-nodes tree. const node = tupleTypeNode([numberTypeNode('u32'), tupleTypeNode([numberTypeNode('u64'), publicKeyTypeNode()])]); // And an extended sum visitor that only visit the first item of tuple nodes. const baseVisitor = mergeVisitor( () => 1, (_, values) => values.reduce((a, b) => a + b, 1), ); const visitor = extendVisitor(baseVisitor, { visitTupleType: (node, { self }) => (node.items.length > 1 ? visit(node.items[0], self) : 0) + 1, }); // When we visit the tree using that visitor. const result = visit(node, visitor); // Then we expect the following count. expect(result).toBe(2); }); test('it cannot extends nodes that are not supported by the base visitor', () => { // Given a base visitor that only supports tuple nodes. const baseVisitor = voidVisitor({ keys: ['tupleTypeNode'] }); // Then we expect an error when we try to extend other nodes for that visitor. expect(() => extendVisitor(baseVisitor, { // @ts-expect-error NumberTypeNode is not part of the base visitor. visitNumberType: () => undefined, }), ).toThrow( new CodamaError(CODAMA_ERROR__VISITORS__CANNOT_EXTEND_MISSING_VISIT_FUNCTION, { visitFunction: 'visitNumberType', }), ); }); ================================================ FILE: packages/visitors-core/test/getByteSizeVisitor.test.ts ================================================ import { accountNode, amountTypeNode, arrayTypeNode, booleanTypeNode, bytesTypeNode, bytesValueNode, constantValueNode, constantValueNodeFromString, dateTimeTypeNode, definedTypeLinkNode, definedTypeNode, enumEmptyVariantTypeNode, enumStructVariantTypeNode, enumTupleVariantTypeNode, enumTypeNode, fixedCountNode, fixedSizeTypeNode, GetNodeFromKind, hiddenPrefixTypeNode, hiddenSuffixTypeNode, instructionArgumentNode, instructionNode, mapTypeNode, NumberFormat, numberTypeNode, numberValueNode, optionTypeNode, postOffsetTypeNode, prefixedCountNode, preOffsetTypeNode, programLinkNode, programNode, publicKeyTypeNode, remainderCountNode, remainderOptionTypeNode, rootNode, sentinelTypeNode, setTypeNode, sizePrefixTypeNode, solAmountTypeNode, stringTypeNode, stringValueNode, structFieldTypeNode, structTypeNode, tupleTypeNode, zeroableOptionTypeNode, } from '@codama/nodes'; import { describe, expect, test } from 'vitest'; import { ByteSizeVisitorKeys, getByteSizeVisitor, getLastNodeFromPath, getRecordLinkablesVisitor, LinkableDictionary, NodePath, NodeStack, visit, } from '../src'; const expectSize = ( node: GetNodeFromKind, expectedSize: number | null, linkables?: LinkableDictionary, stack?: NodeStack, ) => { expect(visit(node, getByteSizeVisitor(linkables ?? new LinkableDictionary(), { stack }))).toBe(expectedSize); }; const expectSizeWithContext = ( nodePath: NodePath>, expectedSize: number | null, ) => { const node = getLastNodeFromPath(nodePath); const stack = new NodeStack(nodePath.slice(0, -1)); const linkables = new LinkableDictionary(); visit(nodePath[0], getRecordLinkablesVisitor(linkables)); expectSize(node, expectedSize, linkables, stack); }; describe('accountNode', () => { test('it returns the size of the account data', () => { expectSize( accountNode({ data: structTypeNode([ structFieldTypeNode({ name: 'mint', type: publicKeyTypeNode() }), structFieldTypeNode({ name: 'owner', type: publicKeyTypeNode() }), structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64') }), ]), name: 'token', }), 32 + 32 + 8, ); }); }); describe('amountTypeNode', () => { test('it delegates to the underlying number type', () => { expectSize(amountTypeNode(numberTypeNode('u64'), 2, 'GBP'), 8); expectSize(amountTypeNode(numberTypeNode('shortU16'), 2, 'GBP'), null); }); }); describe('arrayTypeNode', () => { test('it returns a size if the count is fixed and the inner type is sized', () => { expectSize(arrayTypeNode(numberTypeNode('u16'), fixedCountNode(3)), 2 * 3); }); test('it returns 0 if the count is 0 and the inner type is unsized', () => { expectSize(arrayTypeNode(stringTypeNode('utf8'), fixedCountNode(0)), 0); }); test('it returns null if the count is not fixed', () => { expectSize(arrayTypeNode(numberTypeNode('u16'), prefixedCountNode(numberTypeNode('u8'))), null); expectSize(arrayTypeNode(numberTypeNode('u16'), remainderCountNode()), null); }); test('it returns null if the inner type is unsized', () => { expectSize(arrayTypeNode(stringTypeNode('utf8'), fixedCountNode(3)), null); expectSize(arrayTypeNode(stringTypeNode('utf8'), prefixedCountNode(numberTypeNode('u8'))), null); expectSize(arrayTypeNode(stringTypeNode('utf8'), remainderCountNode()), null); }); test('it returns 0 if the inner type size is 0 and the count is fixed', () => { expectSize(arrayTypeNode(tupleTypeNode([]), fixedCountNode(3)), 0); }); test('it returns 0 if the inner type size is 0 and the count is remainder', () => { expectSize(arrayTypeNode(tupleTypeNode([]), remainderCountNode()), 0); }); test('it returns the prefix size if the inner type size is 0 and the count is prefixed', () => { expectSize(arrayTypeNode(tupleTypeNode([]), prefixedCountNode(numberTypeNode('u32'))), 4); expectSize(arrayTypeNode(tupleTypeNode([]), prefixedCountNode(numberTypeNode('shortU16'))), null); }); }); describe('booleanTypeNode', () => { test('it returns 1 by default', () => { expectSize(booleanTypeNode(), 1); }); test('it delegates to the custom boolean size otherwise', () => { expectSize(booleanTypeNode(numberTypeNode('u64')), 8); expectSize(booleanTypeNode(numberTypeNode('shortU16')), null); }); }); describe('bytesTypeNode', () => { test('it always returns null', () => { expectSize(bytesTypeNode(), null); }); }); describe('constantValueNode', () => { test('it returns the type size if fixed', () => { expectSize(constantValueNode(numberTypeNode('u32'), numberValueNode(42)), 4); expectSize(constantValueNode(fixedSizeTypeNode(stringTypeNode('utf8'), 42), stringValueNode('Hello')), 42); }); test('it returns the size of byte value nodes when used with a base16 encoding', () => { expectSize(constantValueNode(bytesTypeNode(), bytesValueNode('base16', '11223344')), 4); }); test('it returns the size of string value nodes when used with a base16 encoding', () => { expectSize(constantValueNode(stringTypeNode('base16'), stringValueNode('11223344')), 4); }); }); describe('dateTimeTypeNode', () => { test('it delegates to the underlying number type', () => { expectSize(dateTimeTypeNode(numberTypeNode('u64')), 8); expectSize(dateTimeTypeNode(numberTypeNode('shortU16')), null); }); }); describe('definedTypeNode', () => { test('it returns the size of the inner type', () => { expectSize(definedTypeNode({ name: 'fixed', type: numberTypeNode('u32') }), 4); expectSize(definedTypeNode({ name: 'variable', type: stringTypeNode('utf8') }), null); }); }); describe('definedTypeLinkNode', () => { test('it returns the size of the type being linked', () => { const context = programNode({ definedTypes: [definedTypeNode({ name: 'myType', type: numberTypeNode('u64') })], name: 'myProgram', publicKey: '1111', }); expectSizeWithContext([context, definedTypeLinkNode('myType')], 8); }); test('it returns null if the linked type is variable', () => { const context = programNode({ definedTypes: [definedTypeNode({ name: 'myType', type: stringTypeNode('utf8') })], name: 'myProgram', publicKey: '1111', }); expectSizeWithContext([context, definedTypeLinkNode('myType')], null); }); test('it returns null if the linked type cannot be found', () => { const context = programNode({ name: 'myProgram', publicKey: '1111' }); expectSizeWithContext([context, definedTypeLinkNode('myMissingType')], null); }); test('it returns null if the linked type is circular', () => { const context = programNode({ definedTypes: [definedTypeNode({ name: 'myType', type: definedTypeLinkNode('myType') })], name: 'myProgram', publicKey: '1111', }); expectSizeWithContext([context, definedTypeLinkNode('myType')], null); }); test('it follows linked nodes using the correct paths when jumping between programs', () => { const programA = programNode({ definedTypes: [ definedTypeNode({ name: 'typeA', type: definedTypeLinkNode('typeB1', programLinkNode('programB')), }), ], name: 'programA', publicKey: '1111', }); const programB = programNode({ definedTypes: [ definedTypeNode({ name: 'typeB1', type: definedTypeLinkNode('typeB2') }), definedTypeNode({ name: 'typeB2', type: numberTypeNode('u64') }), ], name: 'programB', publicKey: '2222', }); const context = rootNode(programA, [programB]); expectSizeWithContext([context, programA, programA.definedTypes[0]], 8); }); }); describe('enumTypeNode', () => { test('it returns 1 by default for scalar enums', () => { expectSize( enumTypeNode([enumEmptyVariantTypeNode('A'), enumEmptyVariantTypeNode('B'), enumEmptyVariantTypeNode('C')]), 1, ); }); test('it returns the custom size for scalar enums', () => { expectSize( enumTypeNode( [enumEmptyVariantTypeNode('A'), enumEmptyVariantTypeNode('B'), enumEmptyVariantTypeNode('C')], { size: numberTypeNode('u64') }, ), 8, ); }); test('it returns a fixed size for data enums if all variants are the same fixed size', () => { expectSize( enumTypeNode( [ // 4 bytes enumTupleVariantTypeNode('A', tupleTypeNode([numberTypeNode('u32')])), // 4 bytes enumStructVariantTypeNode( 'B', structTypeNode([ structFieldTypeNode({ name: 'x', type: numberTypeNode('u16') }), structFieldTypeNode({ name: 'y', type: numberTypeNode('u16') }), ]), ), ], // 8 bytes prefix { size: numberTypeNode('u64') }, ), 8 + 4, ); }); test('it returns null if variants have different sizes', () => { expectSize( enumTypeNode([ enumTupleVariantTypeNode('A', tupleTypeNode([numberTypeNode('u16')])), // 2 bytes enumTupleVariantTypeNode('B', tupleTypeNode([numberTypeNode('u32')])), // 4 bytes ]), null, ); }); test('it returns null if at least one variant is unsized', () => { expectSize(enumTypeNode([enumTupleVariantTypeNode('A', tupleTypeNode([stringTypeNode('utf8')]))]), null); }); }); describe('fixedSizeTypeNode', () => { test('it returns the fixed size assigned on the node', () => { expectSize(fixedSizeTypeNode(numberTypeNode('u8'), 32), 32); expectSize(fixedSizeTypeNode(stringTypeNode('utf8'), 32), 32); }); }); describe('hiddenPrefixTypeNode', () => { test('it returns the sum of all prefixes and the inner item if all of them are fixed', () => { const prefix1 = constantValueNodeFromString('base16', '2222'); const prefix2 = constantValueNodeFromString('base16', '333333'); expectSize(hiddenPrefixTypeNode(numberTypeNode('u32'), [prefix1, prefix2]), 2 + 3 + 4); }); test('it returns null if the inner item is variable', () => { const prefix = constantValueNodeFromString('base16', 'ffff'); expectSize(hiddenPrefixTypeNode(stringTypeNode('utf8'), [prefix]), null); }); }); describe('hiddenSuffixTypeNode', () => { test('it returns the sum of all suffixes and the inner item if all of them are fixed', () => { const suffix1 = constantValueNodeFromString('base16', '2222'); const suffix2 = constantValueNodeFromString('base16', '333333'); expectSize(hiddenSuffixTypeNode(numberTypeNode('u32'), [suffix1, suffix2]), 4 + 2 + 3); }); test('it returns null if the inner item is variable', () => { const suffix = constantValueNodeFromString('base16', 'ffff'); expectSize(hiddenSuffixTypeNode(stringTypeNode('utf8'), [suffix]), null); }); }); describe('instructionNode', () => { test('it returns the total size of all arguments in the instruction', () => { expectSize( instructionNode({ arguments: [ instructionArgumentNode({ name: 'lamports', type: numberTypeNode('u64') }), instructionArgumentNode({ name: 'space', type: numberTypeNode('u32') }), ], name: 'createAccount', }), 8 + 4, ); }); test('it returns null if any argument is unsized', () => { expectSize( instructionNode({ arguments: [ instructionArgumentNode({ name: 'lamports', type: numberTypeNode('u64') }), instructionArgumentNode({ name: 'name', type: stringTypeNode('utf8') }), ], name: 'createAccount', }), null, ); }); }); describe('instructionArgumentNode', () => { test('it returns the size of the argument type', () => { expectSize(instructionArgumentNode({ name: 'lamports', type: numberTypeNode('u64') }), 8); }); }); describe('mapTypeNode', () => { test('it returns a size if the count is fixed and the inner type is sized', () => { const key = numberTypeNode('u8'); // Fixed const value = numberTypeNode('u16'); // Fixed expectSize(mapTypeNode(key, value, fixedCountNode(3)), (1 + 2) * 3); }); test('it returns 0 if the count is 0 and the inner type is unsized', () => { const key = stringTypeNode('utf8'); // Variable const value = numberTypeNode('u16'); // Fixed expectSize(mapTypeNode(key, value, fixedCountNode(0)), 0); }); test('it returns null if the count is not fixed', () => { const key = numberTypeNode('u8'); // Fixed const value = numberTypeNode('u16'); // Fixed expectSize(mapTypeNode(key, value, prefixedCountNode(numberTypeNode('u8'))), null); expectSize(mapTypeNode(key, value, remainderCountNode()), null); }); test('it returns null if the inner type is unsized', () => { const key = numberTypeNode('u8'); const value = stringTypeNode('utf8'); expectSize(mapTypeNode(key, value, fixedCountNode(3)), null); expectSize(mapTypeNode(key, value, prefixedCountNode(numberTypeNode('u8'))), null); expectSize(mapTypeNode(key, value, remainderCountNode()), null); }); test('it returns 0 if the inner type size is 0 and the count is fixed', () => { const zeroSizeType = tupleTypeNode([]); expectSize(mapTypeNode(zeroSizeType, zeroSizeType, fixedCountNode(3)), 0); }); test('it returns 0 if the inner type size is 0 and the count is remainder', () => { const zeroSizeType = tupleTypeNode([]); expectSize(mapTypeNode(zeroSizeType, zeroSizeType, remainderCountNode()), 0); }); test('it returns the prefix size if the inner type size is 0 and the count is prefixed', () => { const zeroSizeType = tupleTypeNode([]); expectSize(mapTypeNode(zeroSizeType, zeroSizeType, prefixedCountNode(numberTypeNode('u32'))), 4); expectSize(mapTypeNode(zeroSizeType, zeroSizeType, prefixedCountNode(numberTypeNode('shortU16'))), null); }); }); describe('numberTypeNode', () => { test.each([ ['u8', 1], ['i8', 1], ['u16', 2], ['i16', 2], ['u32', 4], ['i32', 4], ['u64', 8], ['i64', 8], ['u128', 16], ['i128', 16], ['f32', 4], ['f64', 8], ])('it returns the size of %s numbers', (format, expectedSize) => { expectSize(numberTypeNode(format as NumberFormat), expectedSize); }); test('it returns null if the format is shortU16', () => { expectSize(numberTypeNode('shortU16'), null); }); }); describe('optionTypeNode', () => { test('it returns the sum of the prefix and the inner item sizes if both of them are fixed', () => { expectSize(optionTypeNode(numberTypeNode('u32'), { fixed: true }), 5); expectSize(optionTypeNode(numberTypeNode('u32'), { fixed: true, prefix: numberTypeNode('u16') }), 6); }); test('it returns null if the inner item is not fixed', () => { expectSize(optionTypeNode(stringTypeNode('utf8'), { fixed: true }), null); }); test('it returns null if the prefixed is not fixed', () => { expectSize(optionTypeNode(numberTypeNode('u32'), { fixed: true, prefix: numberTypeNode('shortU16') }), null); }); test('it returns null if the option is not fixed', () => { expectSize(optionTypeNode(numberTypeNode('u32')), null); expectSize(optionTypeNode(numberTypeNode('u32'), { prefix: numberTypeNode('u16') }), null); }); }); describe('postOffsetTypeNode', () => { test('it increases the size by the offset when using a padded offset', () => { expectSize(postOffsetTypeNode(numberTypeNode('u16'), 10, 'padded'), 12); }); test('it returns null if the inner item is not fixed', () => { expectSize(postOffsetTypeNode(stringTypeNode('utf8'), 4, 'padded'), null); }); test('it returns the size of the inner item for other offset strategies', () => { // Fixed. expectSize(postOffsetTypeNode(numberTypeNode('u8'), 42), 1); expectSize(postOffsetTypeNode(numberTypeNode('u8'), 42, 'absolute'), 1); expectSize(postOffsetTypeNode(numberTypeNode('u8'), 42, 'preOffset'), 1); expectSize(postOffsetTypeNode(numberTypeNode('u8'), 42, 'relative'), 1); // Variable. expectSize(postOffsetTypeNode(stringTypeNode('utf8'), 42), null); expectSize(postOffsetTypeNode(stringTypeNode('utf8'), 42, 'absolute'), null); expectSize(postOffsetTypeNode(stringTypeNode('utf8'), 42, 'preOffset'), null); expectSize(postOffsetTypeNode(stringTypeNode('utf8'), 42, 'relative'), null); }); }); describe('preOffsetTypeNode', () => { test('it increases the size by the offset when using a padded offset', () => { expectSize(preOffsetTypeNode(numberTypeNode('u16'), 10, 'padded'), 12); }); test('it returns null if the inner item is not fixed', () => { expectSize(preOffsetTypeNode(stringTypeNode('utf8'), 4, 'padded'), null); }); test('it returns the size of the inner item for other offset strategies', () => { // Fixed. expectSize(preOffsetTypeNode(numberTypeNode('u8'), 42), 1); expectSize(preOffsetTypeNode(numberTypeNode('u8'), 42, 'absolute'), 1); expectSize(preOffsetTypeNode(numberTypeNode('u8'), 42, 'relative'), 1); // Variable. expectSize(preOffsetTypeNode(stringTypeNode('utf8'), 42), null); expectSize(preOffsetTypeNode(stringTypeNode('utf8'), 42, 'absolute'), null); expectSize(preOffsetTypeNode(stringTypeNode('utf8'), 42, 'relative'), null); }); }); describe('publicKeyTypeNode', () => { test('it returns 32', () => { expectSize(publicKeyTypeNode(), 32); }); }); describe('remainderOptionTypeNode', () => { test('it returns 0 if the inner item size is also 0', () => { expectSize(remainderOptionTypeNode(tupleTypeNode([])), 0); }); test('it returns null in all other cases', () => { expectSize(remainderOptionTypeNode(numberTypeNode('u16')), null); expectSize(remainderOptionTypeNode(stringTypeNode('utf8')), null); }); }); describe('sentinelTypeNode', () => { test('it returns the inner type and the sentinel size if both of them are fixed', () => { const sentinel = constantValueNodeFromString('base16', 'ffff'); expectSize(sentinelTypeNode(numberTypeNode('u32'), sentinel), 6); }); test('it returns null if the inner type is variable', () => { const sentinel = constantValueNodeFromString('base16', 'ffff'); expectSize(sentinelTypeNode(stringTypeNode('utf8'), sentinel), null); }); }); describe('setTypeNode', () => { test('it returns a size if the count is fixed and the inner type is sized', () => { expectSize(setTypeNode(numberTypeNode('u16'), fixedCountNode(3)), 2 * 3); }); test('it returns 0 if the count is 0 and the inner type is unsized', () => { expectSize(setTypeNode(stringTypeNode('utf8'), fixedCountNode(0)), 0); }); test('it returns null if the count is not fixed', () => { expectSize(setTypeNode(numberTypeNode('u16'), prefixedCountNode(numberTypeNode('u8'))), null); expectSize(setTypeNode(numberTypeNode('u16'), remainderCountNode()), null); }); test('it returns null if the inner type is unsized', () => { expectSize(setTypeNode(stringTypeNode('utf8'), fixedCountNode(3)), null); expectSize(setTypeNode(stringTypeNode('utf8'), prefixedCountNode(numberTypeNode('u8'))), null); expectSize(setTypeNode(stringTypeNode('utf8'), remainderCountNode()), null); }); test('it returns 0 if the inner type size is 0 and the count is fixed', () => { expectSize(setTypeNode(tupleTypeNode([]), fixedCountNode(3)), 0); }); test('it returns 0 if the inner type size is 0 and the count is remainder', () => { expectSize(setTypeNode(tupleTypeNode([]), remainderCountNode()), 0); }); test('it returns the prefix size if the inner type size is 0 and the count is prefixed', () => { expectSize(setTypeNode(tupleTypeNode([]), prefixedCountNode(numberTypeNode('u32'))), 4); expectSize(setTypeNode(tupleTypeNode([]), prefixedCountNode(numberTypeNode('shortU16'))), null); }); }); describe('sizePrefixTypeNode', () => { test('it returns the size of the size prefix if the inner type size is 0', () => { expectSize(sizePrefixTypeNode(tupleTypeNode([]), numberTypeNode('u32')), 4); }); test('it returns the sum of the prefix and the inner type if both are fixed', () => { expectSize(sizePrefixTypeNode(publicKeyTypeNode(), numberTypeNode('u32')), 4 + 32); }); test('it returns null if the inner type is variable', () => { expectSize(sizePrefixTypeNode(stringTypeNode('utf8'), numberTypeNode('u32')), null); }); }); describe('solAmountTypeNode', () => { test('it delegates to the underlying number type', () => { expectSize(solAmountTypeNode(numberTypeNode('u64')), 8); expectSize(solAmountTypeNode(numberTypeNode('shortU16')), null); }); }); describe('stringTypeNode', () => { test('it always returns null', () => { expectSize(stringTypeNode('base16'), null); expectSize(stringTypeNode('base58'), null); expectSize(stringTypeNode('base64'), null); expectSize(stringTypeNode('utf8'), null); }); }); describe('structFieldTypeNode', () => { test('it returns the size of the inner type', () => { expectSize(structFieldTypeNode({ name: 'fixed', type: numberTypeNode('u32') }), 4); expectSize(structFieldTypeNode({ name: 'variable', type: stringTypeNode('utf8') }), null); }); }); describe('structTypeNode', () => { test('it returns the sum of fields if all fields are fixed size', () => { expectSize( structTypeNode([ structFieldTypeNode({ name: 'age', type: numberTypeNode('u32') }), structFieldTypeNode({ name: 'firstname', type: fixedSizeTypeNode(stringTypeNode('utf8'), 42) }), ]), 4 + 42, ); }); test('it returns null if any field is variable', () => { expectSize( structTypeNode([ structFieldTypeNode({ name: 'age', type: numberTypeNode('u32') }), structFieldTypeNode({ name: 'firstname', type: stringTypeNode('utf8') }), ]), null, ); }); }); describe('tupleTypeNode', () => { test('it returns the sum of all sizes if all elements are fixed', () => { expectSize(tupleTypeNode([numberTypeNode('u16'), numberTypeNode('u32')]), 2 + 4); }); test('it returns null if any item is variable', () => { expectSize(tupleTypeNode([numberTypeNode('u16'), stringTypeNode('utf8')]), null); }); }); describe('zeroableOptionTypeNode', () => { test('it returns the inner item size if it is fixed', () => { expectSize(zeroableOptionTypeNode(publicKeyTypeNode()), 32); }); test('it returns null if the inner item is variable', () => { expectSize(zeroableOptionTypeNode(stringTypeNode('utf8')), null); }); test('it returns the inner item size if it matches the zero value when provided', () => { const zeroValue = constantValueNodeFromString('base16', 'ffffffff'); expectSize(zeroableOptionTypeNode(numberTypeNode('u32'), zeroValue), 4); }); test('it returns null if the provided zero value does not match the inner item size', () => { const zeroValue = constantValueNodeFromString('base16', 'ffffffff'); expectSize(zeroableOptionTypeNode(numberTypeNode('u64'), zeroValue), null); }); }); ================================================ FILE: packages/visitors-core/test/getDebugStringVisitor.test.ts ================================================ import { enumEmptyVariantTypeNode, enumTypeNode, numberTypeNode, optionTypeNode, publicKeyTypeNode, sizePrefixTypeNode, stringTypeNode, structFieldTypeNode, structTypeNode, tupleTypeNode, } from '@codama/nodes'; import { expect, test } from 'vitest'; import { getDebugStringVisitor, visit } from '../src'; test('it returns a string representing the main information of a node for debugging purposes', () => { // Given the following tree. const node = tupleTypeNode([ numberTypeNode('u32'), structTypeNode([ structFieldTypeNode({ name: 'firstname', type: sizePrefixTypeNode(stringTypeNode('utf8'), numberTypeNode('u64')), }), structFieldTypeNode({ name: 'age', type: numberTypeNode('u32') }), structFieldTypeNode({ name: 'wallet', type: optionTypeNode(publicKeyTypeNode(), { prefix: numberTypeNode('u16'), }), }), structFieldTypeNode({ name: 'industry', type: enumTypeNode([ enumEmptyVariantTypeNode('programming'), enumEmptyVariantTypeNode('crypto'), enumEmptyVariantTypeNode('music'), ]), }), ]), ]); // When we get its unique hash string. const result = visit(node, getDebugStringVisitor()); // Then we expect the following string. expect(result).toEqual( 'tupleTypeNode(numberTypeNode[u32], structTypeNode(structFieldTypeNode[firstname](sizePrefixTypeNode(numberTypeNode[u64], stringTypeNode[utf8])), structFieldTypeNode[age](numberTypeNode[u32]), structFieldTypeNode[wallet](optionTypeNode(numberTypeNode[u16], publicKeyTypeNode)), structFieldTypeNode[industry](enumTypeNode(numberTypeNode[u8], enumEmptyVariantTypeNode[programming], enumEmptyVariantTypeNode[crypto], enumEmptyVariantTypeNode[music]))))', ); }); test('it can create indented strings', () => { // Given the following tree. const node = tupleTypeNode([ numberTypeNode('u32'), structTypeNode([ structFieldTypeNode({ name: 'firstname', type: sizePrefixTypeNode(stringTypeNode('utf8'), numberTypeNode('u64')), }), structFieldTypeNode({ name: 'age', type: numberTypeNode('u32') }), structFieldTypeNode({ name: 'wallet', type: optionTypeNode(publicKeyTypeNode(), { prefix: numberTypeNode('u16'), }), }), structFieldTypeNode({ name: 'industry', type: enumTypeNode([ enumEmptyVariantTypeNode('programming'), enumEmptyVariantTypeNode('crypto'), enumEmptyVariantTypeNode('music'), ]), }), ]), ]); // When we get its unique hash string. const result = visit(node, getDebugStringVisitor({ indent: true })); // Then we expect the following string. expect(result).toEqual(`tupleTypeNode | numberTypeNode [u32] | structTypeNode | | structFieldTypeNode [firstname] | | | sizePrefixTypeNode | | | | numberTypeNode [u64] | | | | stringTypeNode [utf8] | | structFieldTypeNode [age] | | | numberTypeNode [u32] | | structFieldTypeNode [wallet] | | | optionTypeNode | | | | numberTypeNode [u16] | | | | publicKeyTypeNode | | structFieldTypeNode [industry] | | | enumTypeNode | | | | numberTypeNode [u8] | | | | enumEmptyVariantTypeNode [programming] | | | | enumEmptyVariantTypeNode [crypto] | | | | enumEmptyVariantTypeNode [music]`); }); ================================================ FILE: packages/visitors-core/test/getMaxByteSizeVisitor.test.ts ================================================ import { accountNode, amountTypeNode, arrayTypeNode, booleanTypeNode, bytesTypeNode, bytesValueNode, constantValueNode, constantValueNodeFromString, dateTimeTypeNode, definedTypeLinkNode, definedTypeNode, enumEmptyVariantTypeNode, enumTupleVariantTypeNode, enumTypeNode, fixedCountNode, fixedSizeTypeNode, GetNodeFromKind, hiddenPrefixTypeNode, hiddenSuffixTypeNode, instructionArgumentNode, instructionNode, mapTypeNode, NumberFormat, numberTypeNode, numberValueNode, optionTypeNode, postOffsetTypeNode, prefixedCountNode, preOffsetTypeNode, programLinkNode, programNode, publicKeyTypeNode, remainderCountNode, remainderOptionTypeNode, rootNode, sentinelTypeNode, setTypeNode, sizePrefixTypeNode, solAmountTypeNode, someValueNode, stringTypeNode, stringValueNode, structFieldTypeNode, structTypeNode, tupleTypeNode, zeroableOptionTypeNode, } from '@codama/nodes'; import { describe, expect, test } from 'vitest'; import { ByteSizeVisitorKeys, getLastNodeFromPath, getMaxByteSizeVisitor, getRecordLinkablesVisitor, LinkableDictionary, NodePath, NodeStack, visit, } from '../src'; const expectMaxSize = ( node: GetNodeFromKind, expectedMaxSize: number | null, linkables?: LinkableDictionary, stack?: NodeStack, ) => { expect(visit(node, getMaxByteSizeVisitor(linkables ?? new LinkableDictionary(), { stack }))).toBe(expectedMaxSize); }; const expectMaxSizeWithContext = ( nodePath: NodePath>, expectedMaxSize: number | null, ) => { const node = getLastNodeFromPath(nodePath); const stack = new NodeStack(nodePath.slice(0, -1)); const linkables = new LinkableDictionary(); visit(nodePath[0], getRecordLinkablesVisitor(linkables)); expectMaxSize(node, expectedMaxSize, linkables, stack); }; describe('accountNode', () => { test('it returns the max size of the account data', () => { expectMaxSize( accountNode({ data: structTypeNode([ structFieldTypeNode({ name: 'authority', type: publicKeyTypeNode() }), structFieldTypeNode({ name: 'maxSupply', type: optionTypeNode(numberTypeNode('u64')) }), ]), name: 'mint', }), 32 + 9, ); }); }); describe('amountTypeNode', () => { test('it delegates to the underlying number type', () => { expectMaxSize(amountTypeNode(numberTypeNode('u64'), 2, 'GBP'), 8); expectMaxSize(amountTypeNode(numberTypeNode('shortU16'), 2, 'GBP'), 3); }); }); describe('arrayTypeNode', () => { test('it multiplies the max size of the inner item with the fixed count', () => { expectMaxSize(arrayTypeNode(optionTypeNode(numberTypeNode('u32')), fixedCountNode(3)), 5 * 3); }); test('it returns 0 if the count is 0 and the inner type is unsized', () => { expectMaxSize(arrayTypeNode(stringTypeNode('utf8'), fixedCountNode(0)), 0); }); test('it returns null if the count is not fixed', () => { expectMaxSize(arrayTypeNode(numberTypeNode('u16'), prefixedCountNode(numberTypeNode('u8'))), null); expectMaxSize(arrayTypeNode(numberTypeNode('u16'), remainderCountNode()), null); }); test('it returns null if the inner type has no max size', () => { expectMaxSize(arrayTypeNode(stringTypeNode('utf8'), fixedCountNode(3)), null); expectMaxSize(arrayTypeNode(stringTypeNode('utf8'), prefixedCountNode(numberTypeNode('u8'))), null); expectMaxSize(arrayTypeNode(stringTypeNode('utf8'), remainderCountNode()), null); }); test('it returns 0 if the inner type max size is 0 and the count is fixed', () => { expectMaxSize(arrayTypeNode(tupleTypeNode([]), fixedCountNode(3)), 0); }); test('it returns 0 if the inner type max size is 0 and the count is remainder', () => { expectMaxSize(arrayTypeNode(tupleTypeNode([]), remainderCountNode()), 0); }); test('it returns the prefix max size if the inner type size is 0 and the count is prefixed', () => { expectMaxSize(arrayTypeNode(tupleTypeNode([]), prefixedCountNode(numberTypeNode('u32'))), 4); expectMaxSize(arrayTypeNode(tupleTypeNode([]), prefixedCountNode(numberTypeNode('shortU16'))), 3); }); }); describe('booleanTypeNode', () => { test('it returns 1 by default', () => { expectMaxSize(booleanTypeNode(), 1); }); test('it delegates to the custom boolean size otherwise', () => { expectMaxSize(booleanTypeNode(numberTypeNode('u64')), 8); expectMaxSize(booleanTypeNode(numberTypeNode('shortU16')), 3); }); }); describe('bytesTypeNode', () => { test('it always returns null', () => { expectMaxSize(bytesTypeNode(), null); }); }); describe('constantValueNode', () => { test('it returns the type size if it has a max size', () => { expectMaxSize(constantValueNode(optionTypeNode(numberTypeNode('u32')), someValueNode(numberValueNode(42))), 5); expectMaxSize(constantValueNode(fixedSizeTypeNode(stringTypeNode('utf8'), 42), stringValueNode('Hello')), 42); }); test('it returns the size of byte value nodes when used with a base16 encoding', () => { expectMaxSize(constantValueNode(bytesTypeNode(), bytesValueNode('base16', '11223344')), 4); }); test('it returns the size of string value nodes when used with a base16 encoding', () => { expectMaxSize(constantValueNode(stringTypeNode('base16'), stringValueNode('11223344')), 4); }); }); describe('dateTimeTypeNode', () => { test('it delegates to the underlying number type', () => { expectMaxSize(dateTimeTypeNode(numberTypeNode('u64')), 8); expectMaxSize(dateTimeTypeNode(numberTypeNode('shortU16')), 3); }); }); describe('definedTypeNode', () => { test('it returns the size of the inner type', () => { expectMaxSize(definedTypeNode({ name: 'withMaxSize', type: numberTypeNode('shortU16') }), 3); expectMaxSize(definedTypeNode({ name: 'withoutMaxSize', type: stringTypeNode('utf8') }), null); }); }); describe('definedTypeLinkNode', () => { test('it returns the max size of the type being linked', () => { const context = programNode({ definedTypes: [definedTypeNode({ name: 'myType', type: numberTypeNode('shortU16') })], name: 'myProgram', publicKey: '1111', }); expectMaxSizeWithContext([context, definedTypeLinkNode('myType')], 3); }); test('it returns null if the linked type has no max size', () => { const context = programNode({ definedTypes: [definedTypeNode({ name: 'myType', type: stringTypeNode('utf8') })], name: 'myProgram', publicKey: '1111', }); expectMaxSizeWithContext([context, definedTypeLinkNode('myType')], null); }); test('it returns null if the linked type cannot be found', () => { const context = programNode({ name: 'myProgram', publicKey: '1111' }); expectMaxSizeWithContext([context, definedTypeLinkNode('myMissingType')], null); }); test('it returns null if the linked type is circular', () => { const context = programNode({ definedTypes: [definedTypeNode({ name: 'myType', type: definedTypeLinkNode('myType') })], name: 'myProgram', publicKey: '1111', }); expectMaxSizeWithContext([context, definedTypeLinkNode('myType')], null); }); test('it follows linked nodes using the correct paths when jumping between programs', () => { const programA = programNode({ definedTypes: [ definedTypeNode({ name: 'typeA', type: definedTypeLinkNode('typeB1', programLinkNode('programB')), }), ], name: 'programA', publicKey: '1111', }); const programB = programNode({ definedTypes: [ definedTypeNode({ name: 'typeB1', type: definedTypeLinkNode('typeB2') }), definedTypeNode({ name: 'typeB2', type: numberTypeNode('shortU16') }), ], name: 'programB', publicKey: '2222', }); const context = rootNode(programA, [programB]); expectMaxSizeWithContext([context, programA, programA.definedTypes[0]], 3); }); }); describe('enumTypeNode', () => { test('it returns 1 by default for scalar enums', () => { expectMaxSize( enumTypeNode([enumEmptyVariantTypeNode('A'), enumEmptyVariantTypeNode('B'), enumEmptyVariantTypeNode('C')]), 1, ); }); test('it returns the custom size for scalar enums', () => { expectMaxSize( enumTypeNode( [enumEmptyVariantTypeNode('A'), enumEmptyVariantTypeNode('B'), enumEmptyVariantTypeNode('C')], { size: numberTypeNode('shortU16') }, ), 3, ); }); test('it returns the size of the largest variant plus the prefix', () => { expectMaxSize( enumTypeNode( [ enumTupleVariantTypeNode('A', tupleTypeNode([numberTypeNode('u16')])), // 2 bytes enumTupleVariantTypeNode('B', tupleTypeNode([numberTypeNode('u32')])), // 4 bytes ], { size: numberTypeNode('u64') }, ), 8 + 4, ); }); test('it returns null if at least one variant has no max size', () => { expectMaxSize(enumTypeNode([enumTupleVariantTypeNode('A', tupleTypeNode([stringTypeNode('utf8')]))]), null); }); }); describe('fixedSizeTypeNode', () => { test('it returns the fixed size assigned on the node', () => { expectMaxSize(fixedSizeTypeNode(numberTypeNode('u8'), 32), 32); expectMaxSize(fixedSizeTypeNode(stringTypeNode('utf8'), 32), 32); }); }); describe('hiddenPrefixTypeNode', () => { test('it returns the sum of all prefixes and the inner item if all of them have a max size', () => { const prefix1 = constantValueNodeFromString('base16', '2222'); const prefix2 = constantValueNodeFromString('base16', '333333'); expectMaxSize(hiddenPrefixTypeNode(numberTypeNode('shortU16'), [prefix1, prefix2]), 2 + 3 + 3); }); test('it returns null if the inner item has no max size', () => { const prefix = constantValueNodeFromString('base16', 'ffff'); expectMaxSize(hiddenPrefixTypeNode(stringTypeNode('utf8'), [prefix]), null); }); }); describe('hiddenSuffixTypeNode', () => { test('it returns the sum of all suffixes and the inner item if all of them have a max size', () => { const suffix1 = constantValueNodeFromString('base16', '2222'); const suffix2 = constantValueNodeFromString('base16', '333333'); expectMaxSize(hiddenSuffixTypeNode(numberTypeNode('shortU16'), [suffix1, suffix2]), 3 + 2 + 3); }); test('it returns null if the inner item has no max size', () => { const suffix = constantValueNodeFromString('base16', 'ffff'); expectMaxSize(hiddenSuffixTypeNode(stringTypeNode('utf8'), [suffix]), null); }); }); describe('instructionNode', () => { test('it returns the total max size of all arguments in the instruction', () => { expectMaxSize( instructionNode({ arguments: [ instructionArgumentNode({ name: 'lamports', type: optionTypeNode(numberTypeNode('u64')) }), instructionArgumentNode({ name: 'space', type: numberTypeNode('shortU16') }), ], name: 'createAccount', }), 9 + 3, ); }); test('it returns null if any argument has no max size', () => { expectMaxSize( instructionNode({ arguments: [ instructionArgumentNode({ name: 'lamports', type: numberTypeNode('u64') }), instructionArgumentNode({ name: 'name', type: stringTypeNode('utf8') }), ], name: 'createAccount', }), null, ); }); }); describe('instructionArgumentNode', () => { test('it returns the max size of the argument type', () => { expectMaxSize(instructionArgumentNode({ name: 'lamports', type: numberTypeNode('shortU16') }), 3); }); }); describe('mapTypeNode', () => { test('it multiplies the max size of the inner item with the fixed count', () => { const key = numberTypeNode('u8'); const value = optionTypeNode(numberTypeNode('u16')); expectMaxSize(mapTypeNode(key, value, fixedCountNode(4)), (1 + 3) * 4); }); test('it returns 0 if the count is 0 and the inner type is unsized', () => { const key = stringTypeNode('utf8'); const value = numberTypeNode('u16'); expectMaxSize(mapTypeNode(key, value, fixedCountNode(0)), 0); }); test('it returns null if the count is not fixed', () => { const key = numberTypeNode('u8'); const value = numberTypeNode('u16'); expectMaxSize(mapTypeNode(key, value, prefixedCountNode(numberTypeNode('u8'))), null); expectMaxSize(mapTypeNode(key, value, remainderCountNode()), null); }); test('it returns null if the inner type has no max size', () => { const key = numberTypeNode('u8'); const value = stringTypeNode('utf8'); expectMaxSize(mapTypeNode(key, value, fixedCountNode(3)), null); expectMaxSize(mapTypeNode(key, value, prefixedCountNode(numberTypeNode('u8'))), null); expectMaxSize(mapTypeNode(key, value, remainderCountNode()), null); }); test('it returns 0 if the inner type max size is 0 and the count is fixed', () => { const zeroSizeType = tupleTypeNode([]); expectMaxSize(mapTypeNode(zeroSizeType, zeroSizeType, fixedCountNode(3)), 0); }); test('it returns 0 if the inner type max size is 0 and the count is remainder', () => { const zeroSizeType = tupleTypeNode([]); expectMaxSize(mapTypeNode(zeroSizeType, zeroSizeType, remainderCountNode()), 0); }); test('it returns the prefix max size if the inner type size is 0 and the count is prefixed', () => { const zeroSizeType = tupleTypeNode([]); expectMaxSize(mapTypeNode(zeroSizeType, zeroSizeType, prefixedCountNode(numberTypeNode('u32'))), 4); expectMaxSize(mapTypeNode(zeroSizeType, zeroSizeType, prefixedCountNode(numberTypeNode('shortU16'))), 3); }); }); describe('numberTypeNode', () => { test.each([ ['u8', 1], ['i8', 1], ['u16', 2], ['i16', 2], ['u32', 4], ['i32', 4], ['u64', 8], ['i64', 8], ['u128', 16], ['i128', 16], ['f32', 4], ['f64', 8], ['shortU16', 3], ])('it returns the size of %s numbers', (format, expectedSize) => { expectMaxSize(numberTypeNode(format as NumberFormat), expectedSize); }); }); describe('optionTypeNode', () => { test('it returns the max size of the inner item plus 1 by default', () => { expectMaxSize(optionTypeNode(numberTypeNode('u32')), 1 + 4); expectMaxSize(optionTypeNode(numberTypeNode('u32'), { fixed: true }), 1 + 4); }); test('it returns the sum of the prefix and inner item max sizes', () => { expectMaxSize(optionTypeNode(numberTypeNode('u32'), { prefix: numberTypeNode('u16') }), 2 + 4); expectMaxSize(optionTypeNode(numberTypeNode('u32'), { fixed: true, prefix: numberTypeNode('u16') }), 2 + 4); }); }); describe('postOffsetTypeNode', () => { test('it increases the max size by the offset when using a padded offset', () => { expectMaxSize(postOffsetTypeNode(numberTypeNode('shortU16'), 10, 'padded'), 13); }); test('it returns null if the inner item is has no max size', () => { expectMaxSize(postOffsetTypeNode(stringTypeNode('utf8'), 4, 'padded'), null); }); test('it returns the max size of the inner item for other offset strategies', () => { // Fixed. expectMaxSize(postOffsetTypeNode(numberTypeNode('shortU16'), 42), 3); expectMaxSize(postOffsetTypeNode(numberTypeNode('shortU16'), 42, 'absolute'), 3); expectMaxSize(postOffsetTypeNode(numberTypeNode('shortU16'), 42, 'preOffset'), 3); expectMaxSize(postOffsetTypeNode(numberTypeNode('shortU16'), 42, 'relative'), 3); // Variable. expectMaxSize(postOffsetTypeNode(stringTypeNode('utf8'), 42), null); expectMaxSize(postOffsetTypeNode(stringTypeNode('utf8'), 42, 'absolute'), null); expectMaxSize(postOffsetTypeNode(stringTypeNode('utf8'), 42, 'preOffset'), null); expectMaxSize(postOffsetTypeNode(stringTypeNode('utf8'), 42, 'relative'), null); }); }); describe('preOffsetTypeNode', () => { test('it increases the max size by the offset when using a padded offset', () => { expectMaxSize(preOffsetTypeNode(numberTypeNode('shortU16'), 10, 'padded'), 13); }); test('it returns null if the inner item has no max size', () => { expectMaxSize(preOffsetTypeNode(stringTypeNode('utf8'), 4, 'padded'), null); }); test('it returns the max size of the inner item for other offset strategies', () => { // Fixed. expectMaxSize(preOffsetTypeNode(numberTypeNode('shortU16'), 42), 3); expectMaxSize(preOffsetTypeNode(numberTypeNode('shortU16'), 42, 'absolute'), 3); expectMaxSize(preOffsetTypeNode(numberTypeNode('shortU16'), 42, 'relative'), 3); // Variable. expectMaxSize(preOffsetTypeNode(stringTypeNode('utf8'), 42), null); expectMaxSize(preOffsetTypeNode(stringTypeNode('utf8'), 42, 'absolute'), null); expectMaxSize(preOffsetTypeNode(stringTypeNode('utf8'), 42, 'relative'), null); }); }); describe('publicKeyTypeNode', () => { test('it returns 32', () => { expectMaxSize(publicKeyTypeNode(), 32); }); }); describe('remainderOptionTypeNode', () => { test('it returns 0 if the inner item max size is also 0', () => { expectMaxSize(remainderOptionTypeNode(tupleTypeNode([])), 0); }); test('it returns null in all other cases', () => { expectMaxSize(remainderOptionTypeNode(numberTypeNode('u16')), null); expectMaxSize(remainderOptionTypeNode(stringTypeNode('utf8')), null); }); }); describe('sentinelTypeNode', () => { test('it returns the sum of the inner type and the sentinel max sizes if both of them exist', () => { const sentinel = constantValueNodeFromString('base16', 'ffff'); expectMaxSize(sentinelTypeNode(numberTypeNode('shortU16'), sentinel), 2 + 3); }); test('it returns null if the inner type has no max size', () => { const sentinel = constantValueNodeFromString('base16', 'ffff'); expectMaxSize(sentinelTypeNode(stringTypeNode('utf8'), sentinel), null); }); }); describe('setTypeNode', () => { test('it multiplies the max size of the inner item with the fixed count', () => { expectMaxSize(setTypeNode(optionTypeNode(numberTypeNode('u32')), fixedCountNode(3)), 5 * 3); }); test('it returns 0 if the count is 0 and the inner type is unsized', () => { expectMaxSize(setTypeNode(stringTypeNode('utf8'), fixedCountNode(0)), 0); }); test('it returns null if the count is not fixed', () => { expectMaxSize(setTypeNode(numberTypeNode('u16'), prefixedCountNode(numberTypeNode('u8'))), null); expectMaxSize(setTypeNode(numberTypeNode('u16'), remainderCountNode()), null); }); test('it returns null if the inner type has no max size', () => { expectMaxSize(setTypeNode(stringTypeNode('utf8'), fixedCountNode(3)), null); expectMaxSize(setTypeNode(stringTypeNode('utf8'), prefixedCountNode(numberTypeNode('u8'))), null); expectMaxSize(setTypeNode(stringTypeNode('utf8'), remainderCountNode()), null); }); test('it returns 0 if the inner type max size is 0 and the count is fixed', () => { expectMaxSize(setTypeNode(tupleTypeNode([]), fixedCountNode(3)), 0); }); test('it returns 0 if the inner type max size is 0 and the count is remainder', () => { expectMaxSize(setTypeNode(tupleTypeNode([]), remainderCountNode()), 0); }); test('it returns the prefix max size if the inner type size is 0 and the count is prefixed', () => { expectMaxSize(setTypeNode(tupleTypeNode([]), prefixedCountNode(numberTypeNode('u32'))), 4); expectMaxSize(setTypeNode(tupleTypeNode([]), prefixedCountNode(numberTypeNode('shortU16'))), 3); }); }); describe('sizePrefixTypeNode', () => { test('it returns the max size of the prefix if the inner type size is 0', () => { expectMaxSize(sizePrefixTypeNode(tupleTypeNode([]), numberTypeNode('shortU16')), 3); }); test('it returns the sum of the prefix and the inner type max sizes if they both exist', () => { expectMaxSize(sizePrefixTypeNode(optionTypeNode(publicKeyTypeNode()), numberTypeNode('shortU16')), 3 + 33); }); test('it returns null if the inner type has no max size', () => { expectMaxSize(sizePrefixTypeNode(stringTypeNode('utf8'), numberTypeNode('u32')), null); }); }); describe('solAmountTypeNode', () => { test('it delegates to the underlying number type', () => { expectMaxSize(solAmountTypeNode(numberTypeNode('u64')), 8); expectMaxSize(solAmountTypeNode(numberTypeNode('shortU16')), 3); }); }); describe('stringTypeNode', () => { test('it always returns null', () => { expectMaxSize(stringTypeNode('base16'), null); expectMaxSize(stringTypeNode('base58'), null); expectMaxSize(stringTypeNode('base64'), null); expectMaxSize(stringTypeNode('utf8'), null); }); }); describe('structFieldTypeNode', () => { test('it returns the max size of the inner type', () => { expectMaxSize(structFieldTypeNode({ name: 'withMaxSize', type: numberTypeNode('shortU16') }), 3); expectMaxSize(structFieldTypeNode({ name: 'withoutMaxSize', type: stringTypeNode('utf8') }), null); }); }); describe('structTypeNode', () => { test('it returns the sum of the field max sizes if they all have one', () => { expectMaxSize( structTypeNode([ structFieldTypeNode({ name: 'age', type: numberTypeNode('shortU16') }), structFieldTypeNode({ name: 'firstname', type: optionTypeNode(fixedSizeTypeNode(stringTypeNode('utf8'), 42)), }), ]), 3 + 43, ); }); test('it returns null if any field has no max size', () => { expectMaxSize( structTypeNode([ structFieldTypeNode({ name: 'age', type: numberTypeNode('u32') }), structFieldTypeNode({ name: 'firstname', type: stringTypeNode('utf8') }), ]), null, ); }); }); describe('tupleTypeNode', () => { test('it returns the sum of all max sizes if all items have one', () => { expectMaxSize(tupleTypeNode([numberTypeNode('shortU16'), optionTypeNode(numberTypeNode('u32'))]), 3 + 5); }); test('it returns null if any item has no max size', () => { expectMaxSize(tupleTypeNode([numberTypeNode('u16'), stringTypeNode('utf8')]), null); }); }); describe('zeroableOptionTypeNode', () => { test('it returns the inner item max size if is has one', () => { expectMaxSize(zeroableOptionTypeNode(numberTypeNode('shortU16')), 3); }); test('it returns null if the inner item has no max size', () => { expectMaxSize(zeroableOptionTypeNode(stringTypeNode('utf8')), null); }); test('it returns the maximum value between the inner item max size and the zero value when provided', () => { const zeroValue = (bytes: number) => constantValueNodeFromString('base16', 'ff'.repeat(bytes)); expectMaxSize(zeroableOptionTypeNode(numberTypeNode('u32'), zeroValue(2)), 4); expectMaxSize(zeroableOptionTypeNode(numberTypeNode('u32'), zeroValue(42)), 42); }); }); ================================================ FILE: packages/visitors-core/test/getResolvedInstructionInputsVisitor.test.ts ================================================ import { accountValueNode, instructionAccountNode, instructionArgumentNode, instructionNode, numberTypeNode, pdaSeedValueNode, pdaValueNode, publicKeyTypeNode, } from '@codama/nodes'; import { expect, test } from 'vitest'; import { getResolvedInstructionInputsVisitor, visit } from '../src'; test('it returns all instruction accounts in order of resolution', () => { // Given the following instruction node with an account that defaults to another account. const node = instructionNode({ accounts: [ instructionAccountNode({ defaultValue: accountValueNode('authority'), isSigner: true, isWritable: false, name: 'owner', }), instructionAccountNode({ isSigner: true, isWritable: false, name: 'authority', }), ], name: 'myInstruction', }); // When we get its resolved inputs. const result = visit(node, getResolvedInstructionInputsVisitor()); // Then we expect the accounts to be in order of resolution. expect(result).toEqual([ { ...node.accounts[1], dependsOn: [], isPda: false, resolvedIsOptional: false, resolvedIsSigner: true, }, { ...node.accounts[0], dependsOn: [accountValueNode('authority')], isPda: false, resolvedIsOptional: false, resolvedIsSigner: true, }, ]); }); test('it sets the resolved signer to either when a non signer defaults to a signer account', () => { // Given the following instruction node such that a non signer account defaults to a signer account. const node = instructionNode({ accounts: [ instructionAccountNode({ defaultValue: accountValueNode('authority'), isSigner: false, isWritable: false, name: 'owner', }), instructionAccountNode({ isSigner: true, isWritable: false, name: 'authority', }), ], name: 'myInstruction', }); // When we get its resolved inputs. const result = visit(node, getResolvedInstructionInputsVisitor()); // Then we expect the resolved signer to be either for the non signer account. expect(result[1]).toEqual({ ...node.accounts[0], dependsOn: [accountValueNode('authority')], isPda: false, resolvedIsOptional: false, resolvedIsSigner: 'either', }); }); test('it sets the resolved signer to either when a signer defaults to a non signer account', () => { // Given the following instruction node such that a signer account defaults to a non signer account. const node = instructionNode({ accounts: [ instructionAccountNode({ defaultValue: accountValueNode('authority'), isSigner: true, isWritable: false, name: 'owner', }), instructionAccountNode({ isSigner: false, isWritable: false, name: 'authority', }), ], name: 'myInstruction', }); // When we get its resolved inputs. const result = visit(node, getResolvedInstructionInputsVisitor()); // Then we expect the resolved signer to be either for the signer account. expect(result[1]).toEqual({ ...node.accounts[0], dependsOn: [accountValueNode('authority')], isPda: false, resolvedIsOptional: false, resolvedIsSigner: 'either', }); }); test('it includes instruction data arguments with default values', () => { // Given the following instruction node with two arguments such that: // - The first argument defaults to an account. // - The second argument has no default value. const node = instructionNode({ accounts: [ instructionAccountNode({ isSigner: true, isWritable: false, name: 'owner', }), ], arguments: [ instructionArgumentNode({ defaultValue: accountValueNode('owner'), name: 'ownerArg', type: publicKeyTypeNode(), }), instructionArgumentNode({ name: 'argWithoutDefaults', type: numberTypeNode('u8'), }), ], name: 'myInstruction', }); // When we get its resolved inputs. const result = visit(node, getResolvedInstructionInputsVisitor()); // Then we expect the following inputs. expect(result).toEqual([ { ...node.accounts[0], dependsOn: [], isPda: false, resolvedIsOptional: false, resolvedIsSigner: true, }, { ...node.arguments[0], dependsOn: [accountValueNode('owner')], }, ]); // And the argument without default value is not included. expect(result.some(input => input.name === 'argWithoutDefaults')).toBe(false); }); test('it includes instruction extra arguments with default values', () => { // Given the following instruction node with two extra arguments such that: // - The first argument defaults to an account. // - The second argument has no default value. const node = instructionNode({ accounts: [ instructionAccountNode({ isSigner: true, isWritable: false, name: 'owner', }), ], extraArguments: [ instructionArgumentNode({ defaultValue: accountValueNode('owner'), name: 'ownerArg', type: publicKeyTypeNode(), }), instructionArgumentNode({ name: 'argWithoutDefaults', type: numberTypeNode('u8'), }), ], name: 'myInstruction', }); // When we get its resolved inputs. const result = visit(node, getResolvedInstructionInputsVisitor()); // Then we expect the following inputs. expect(result).toEqual([ { ...node.accounts[0], dependsOn: [], isPda: false, resolvedIsOptional: false, resolvedIsSigner: true, }, { ...node.extraArguments![0], dependsOn: [accountValueNode('owner')], }, ]); // And the argument without default value is not included. expect(result.some(input => input.name === 'argWithoutDefaults')).toBe(false); }); test('it returns an empty array for empty instructions', () => { // Given the following empty instruction node. const node = instructionNode({ name: 'myInstruction' }); // When we get its resolved inputs. const result = visit(node, getResolvedInstructionInputsVisitor()); // Then we expect an empty array. expect(result).toEqual([]); }); test('it resolves the seeds of a PdaValueNode first', () => { // Given the following instruction node with an account that defaults to another account. const node = instructionNode({ accounts: [ instructionAccountNode({ defaultValue: pdaValueNode('counter', [pdaSeedValueNode('authority', accountValueNode('payer'))]), isSigner: false, isWritable: false, name: 'counter', }), instructionAccountNode({ isSigner: true, isWritable: false, name: 'payer', }), ], name: 'myInstruction', }); // When we get its resolved inputs. const result = visit(node, getResolvedInstructionInputsVisitor()); // Then we expect the accounts to be in order of resolution. expect(result).toEqual([ { ...node.accounts[1], dependsOn: [], isPda: false, resolvedIsOptional: false, resolvedIsSigner: true, }, { ...node.accounts[0], dependsOn: [accountValueNode('payer')], isPda: false, resolvedIsOptional: false, resolvedIsSigner: false, }, ]); }); test('it resolves the program id of a PdaValueNode first', () => { // Given the following instruction node with an account that defaults to another account. const node = instructionNode({ accounts: [ instructionAccountNode({ defaultValue: pdaValueNode('counter', [], accountValueNode('counterProgram')), isSigner: false, isWritable: false, name: 'counter', }), instructionAccountNode({ isSigner: false, isWritable: false, name: 'counterProgram', }), ], name: 'myInstruction', }); // When we get its resolved inputs. const result = visit(node, getResolvedInstructionInputsVisitor()); // Then we expect the accounts to be in order of resolution. expect(result).toEqual([ { ...node.accounts[1], dependsOn: [], isPda: false, resolvedIsOptional: false, resolvedIsSigner: false, }, { ...node.accounts[0], dependsOn: [accountValueNode('counterProgram')], isPda: false, resolvedIsOptional: false, resolvedIsSigner: false, }, ]); }); ================================================ FILE: packages/visitors-core/test/getUniqueHashStringVisitor.test.ts ================================================ import { numberTypeNode, publicKeyTypeNode, structFieldTypeNode, structTypeNode, tupleTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { getUniqueHashStringVisitor, visit } from '../src'; test('it returns a unique string representing the whole node', () => { // Given the following tree. const node = tupleTypeNode([numberTypeNode('u32'), tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()])]); // When we get its unique hash string. const result = visit(node, getUniqueHashStringVisitor()); // Then we expect the following string. expect(result).toEqual( '{"items":[' + '{"endian":"le","format":"u32","kind":"numberTypeNode"},' + '{"items":[{"endian":"le","format":"u32","kind":"numberTypeNode"},{"kind":"publicKeyTypeNode"}],"kind":"tupleTypeNode"}' + '],"kind":"tupleTypeNode"}', ); }); test('it returns a unique string whilst discard docs', () => { // Given the following tree with docs. const node = structTypeNode([ structFieldTypeNode({ docs: ['The owner of the account.'], name: 'owner', type: publicKeyTypeNode(), }), ]); // When we get its unique hash string whilst discarding docs. const result = visit(node, getUniqueHashStringVisitor({ removeDocs: true })); // Then we expect the following string. expect(result).toEqual( '{"fields":[' + '{"docs":[],"kind":"structFieldTypeNode","name":"owner","type":{"kind":"publicKeyTypeNode"}}' + '],"kind":"structTypeNode"}', ); }); ================================================ FILE: packages/visitors-core/test/identityVisitor.test.ts ================================================ import { assertIsNode, numberTypeNode, publicKeyTypeNode, tupleTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { identityVisitor, interceptVisitor, visit } from '../src'; test('it visits all nodes and returns different instances of the same nodes', () => { // Given the following 3-nodes tree. const node = tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()]); // When we visit it using the identity visitor. const result = visit(node, identityVisitor()); // Then we get the same tree back. expect(result).toEqual(node); // But the nodes are different instances. expect(result).not.toBe(node); assertIsNode(result, 'tupleTypeNode'); expect(result.items[0]).not.toBe(node.items[0]); expect(result.items[1]).not.toBe(node.items[1]); }); test('it can remove nodes by returning null', () => { // Given the following 3-nodes tree. const node = tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()]); // And given an identity visitor overidden to remove all public key nodes. const visitor = identityVisitor(); visitor.visitPublicKeyType = () => null; // When we visit it using that visitor. const result = visit(node, visitor); // Then we expect the following tree back. expect(result).toEqual(tupleTypeNode([numberTypeNode('u32')])); }); test('it can create partial visitors', () => { // Given the following 3-nodes tree. const node = tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()]); // And an identity visitor that only supports 2 of these nodes // whilst using an interceptor to record the events that happened. const events: string[] = []; const visitor = interceptVisitor(identityVisitor({ keys: ['tupleTypeNode', 'numberTypeNode'] }), (node, next) => { events.push(`visiting:${node.kind}`); return next(node); }); // When we visit the tree using that visitor. const result = visit(node, visitor); // Then we still get the full tree back as different instances. expect(result).toEqual(node); expect(result).not.toBe(node); assertIsNode(result, 'tupleTypeNode'); expect(result.items[0]).not.toBe(node.items[0]); expect(result.items[1]).not.toBe(node.items[1]); // But the unsupported node was not visited. expect(events).toEqual(['visiting:tupleTypeNode', 'visiting:numberTypeNode']); // And the unsupported node cannot be visited. // @ts-expect-error PublicKeyTypeNode is not supported. expect(() => visit(publicKeyTypeNode(), visitor)).toThrow(); }); ================================================ FILE: packages/visitors-core/test/interceptFirstVisitVisitor.test.ts ================================================ import { numberTypeNode, publicKeyTypeNode, tupleTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { extendVisitor, interceptFirstVisitVisitor, visit, voidVisitor } from '../src'; test('it returns a new visitor that only intercepts the first visit of a visitor', () => { // Given the following 3-nodes tree. const node = tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()]); // And an intercepted void visitor that records the events that happened during the first visit. const events: string[] = []; const baseVisitor = voidVisitor(); const visitor = interceptFirstVisitVisitor(baseVisitor, (node, next) => { events.push(`down:${node.kind}`); next(node); events.push(`up:${node.kind}`); }); // When we visit the tree using that visitor. visit(node, visitor); // Then we expect the following events to have happened. expect(events).toEqual(['down:tupleTypeNode', 'up:tupleTypeNode']); // And the intercepted visitor is a new instance. expect(baseVisitor).not.toBe(visitor); }); test('it still works on subsequent calls', () => { // Given the following 3-nodes tree. const node = tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()]); // And an intercepted void visitor that records the events that happened during the first visit. const events: string[] = []; const baseVisitor = voidVisitor(); const visitor = interceptFirstVisitVisitor(baseVisitor, (node, next) => { events.push(`intercepting:${node.kind}`); next(node); }); // When we visit the tree twice using that visitor. visit(node, visitor); visit(node, visitor); // Then we expect the following events to have happened. expect(events).toEqual(['intercepting:tupleTypeNode', 'intercepting:tupleTypeNode']); }); test('it resets the first visit boolean if an error is thrown', () => { // Given the following 3-nodes tree. const node = tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()]); // And an intercepted visitor that records the events that happened during the first visit // but throws an error when it visits publicKeyTypeNodes. const events: string[] = []; const baseVisitor = extendVisitor(voidVisitor(), { visitPublicKeyType: () => { throw new Error('public key error'); }, }); const visitor = interceptFirstVisitVisitor(baseVisitor, (node, next) => { events.push(`intercepting:${node.kind}`); next(node); }); // Then we expect errors to be thrown whenever we visit the three. expect(() => visit(node, visitor)).toThrow('public key error'); expect(() => visit(node, visitor)).toThrow('public key error'); // But we still expect the following events to have happened. expect(events).toEqual(['intercepting:tupleTypeNode', 'intercepting:tupleTypeNode']); }); ================================================ FILE: packages/visitors-core/test/interceptVisitor.test.ts ================================================ import { numberTypeNode, publicKeyTypeNode, tupleTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { interceptVisitor, visit, voidVisitor } from '../src'; test('it returns a new visitor that intercepts all visits of a visitor', () => { // Given the following 3-nodes tree. const node = tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()]); // And an intercepted void visitor that records the events that happened during each visit. const events: string[] = []; const baseVisitor = voidVisitor(); const visitor = interceptVisitor(baseVisitor, (node, next) => { events.push(`down:${node.kind}`); next(node); events.push(`up:${node.kind}`); }); // When we visit the tree using that visitor. visit(node, visitor); // Then we expect the following events to have happened. expect(events).toEqual([ 'down:tupleTypeNode', 'down:numberTypeNode', 'up:numberTypeNode', 'down:publicKeyTypeNode', 'up:publicKeyTypeNode', 'up:tupleTypeNode', ]); // And the intercepted visitor is a new instance. expect(baseVisitor).not.toBe(visitor); }); ================================================ FILE: packages/visitors-core/test/mapVisitor.test.ts ================================================ import { numberTypeNode, publicKeyTypeNode, tupleTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { mapVisitor, mergeVisitor, staticVisitor, visit, Visitor } from '../src'; test('it maps the return value of a visitor to another', () => { // Given the following 3-nodes tree. const node = tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()]); // And a merge visitor A that lists the kind of each node. const visitorA = mergeVisitor( node => node.kind as string, (node, values) => `${node.kind}(${values.join(',')})`, ); // And a mapped visitor B that returns the number of characters returned by visitor A. const visitorB = mapVisitor(visitorA, value => value.length); // Then we expect the following results when visiting different nodes. expect(visit(node, visitorB)).toBe(47); expect(visit(node.items[0], visitorB)).toBe(14); expect(visit(node.items[1], visitorB)).toBe(17); }); test('it creates partial visitors from partial visitors', () => { // Given the following 3-nodes tree. const node = tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()]); // And partial static visitor A that supports only 2 of these nodes. const visitorA = staticVisitor(node => node.kind, { keys: ['tupleTypeNode', 'numberTypeNode'] }); // And a mapped visitor B that returns the number of characters returned by visitor A. const visitorB = mapVisitor(visitorA, value => value.length); // Then both visitors are partial. visitorA satisfies Visitor; visitorB satisfies Visitor; // Then we expect an error when visiting an unsupported node. // @ts-expect-error PublicKeyTypeNode is not supported. expect(() => visit(node.items[1], visitorB)).toThrow(); }); ================================================ FILE: packages/visitors-core/test/mergeVisitor.test.ts ================================================ import { numberTypeNode, publicKeyTypeNode, tupleTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { mergeVisitor, visit } from '../src'; test('it sets a value for all leaves and merges node values together', () => { // Given the following 3-nodes tree. const node = tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()]); // And a visitor that sets the node kind for all leaves and combines // them together such that each node lists the kind of its children. const visitor = mergeVisitor( node => node.kind as string, (node, values) => `${node.kind}(${values.join(',')})`, ); // When we visit the tree using that visitor. const result = visit(node, visitor); // Then we get the following result. expect(result).toBe('tupleTypeNode(numberTypeNode,publicKeyTypeNode)'); }); test('it can be used to count nodes', () => { // Given the following 3-nodes tree. const node = tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()]); // When we visit the tree with a visitor that counts nodes. const visitor = mergeVisitor( () => 1, (_, values) => values.reduce((a, b) => a + b, 1), ); const result = visit(node, visitor); // Then we expect to have 3 nodes. expect(result).toBe(3); }); test('it can create partial visitors', () => { // Given the following 3-nodes tree. const node = tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()]); // And a visitor that only supports 2 of these nodes. const visitor = mergeVisitor( node => node.kind as string, (node, values) => `${node.kind}(${values.join(',')})`, { keys: ['tupleTypeNode', 'numberTypeNode'] }, ); // When we visit the tree using that visitor. const result = visit(node, visitor); // Then the unsupported node is not included in the result. expect(result).toBe('tupleTypeNode(numberTypeNode)'); // And the unsupported node cannot be visited. // @ts-expect-error PublicKeyTypeNode is not supported. expect(() => visit(publicKeyTypeNode(), visitor)).toThrow(); }); ================================================ FILE: packages/visitors-core/test/nodes/AccountNode.test.ts ================================================ import { accountNode, numberTypeNode, pdaLinkNode, publicKeyTypeNode, sizeDiscriminatorNode, structFieldTypeNode, structTypeNode, } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from './_setup'; const node = accountNode({ data: structTypeNode([ structFieldTypeNode({ name: 'mint', type: publicKeyTypeNode() }), structFieldTypeNode({ name: 'owner', type: publicKeyTypeNode() }), structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64') }), ]), discriminators: [sizeDiscriminatorNode(72)], name: 'token', pda: pdaLinkNode('associatedToken'), size: 72, }); test('mergeVisitor', () => { expectMergeVisitorCount(node, 10); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[accountNode]', null); expectDeleteNodesVisitor(node, '[pdaLinkNode]', accountNode({ ...node, pda: undefined })); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` accountNode [token] | structTypeNode | | structFieldTypeNode [mint] | | | publicKeyTypeNode | | structFieldTypeNode [owner] | | | publicKeyTypeNode | | structFieldTypeNode [amount] | | | numberTypeNode [u64] | pdaLinkNode [associatedToken] | sizeDiscriminatorNode [72]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/DefinedTypeNode.test.ts ================================================ import { definedTypeNode, fixedSizeTypeNode, numberTypeNode, stringTypeNode, structFieldTypeNode, structTypeNode, } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from './_setup'; const node = definedTypeNode({ name: 'person', type: structTypeNode([ structFieldTypeNode({ name: 'name', type: fixedSizeTypeNode(stringTypeNode('utf8'), 42), }), structFieldTypeNode({ name: 'age', type: numberTypeNode('u64') }), ]), }); test('mergeVisitor', () => { expectMergeVisitorCount(node, 7); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[definedTypeNode]', null); expectDeleteNodesVisitor(node, '[structTypeNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` definedTypeNode [person] | structTypeNode | | structFieldTypeNode [name] | | | fixedSizeTypeNode [42] | | | | stringTypeNode [utf8] | | structFieldTypeNode [age] | | | numberTypeNode [u64]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/ErrorNode.test.ts ================================================ import { errorNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from './_setup'; const node = errorNode({ code: 42, message: 'The provided account does not match the owner of the token account.', name: 'InvalidTokenOwner', }); test('mergeVisitor', () => { expectMergeVisitorCount(node, 1); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[errorNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor(node, `errorNode [42.invalidTokenOwner]`); }); ================================================ FILE: packages/visitors-core/test/nodes/EventNode.test.ts ================================================ import { eventNode, numberTypeNode, publicKeyTypeNode, sizeDiscriminatorNode, structFieldTypeNode, structTypeNode, } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from './_setup'; const node = eventNode({ data: structTypeNode([ structFieldTypeNode({ name: 'authority', type: publicKeyTypeNode() }), structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64') }), ]), discriminators: [sizeDiscriminatorNode(40)], name: 'transferEvent', }); test('mergeVisitor', () => { expectMergeVisitorCount(node, 7); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[eventNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` eventNode [transferEvent] | structTypeNode | | structFieldTypeNode [authority] | | | publicKeyTypeNode | | structFieldTypeNode [amount] | | | numberTypeNode [u64] | sizeDiscriminatorNode [40]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/InstructionAccountNode.test.ts ================================================ import { accountValueNode, instructionAccountNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from './_setup'; const node = instructionAccountNode({ defaultValue: accountValueNode('authority'), isOptional: false, isSigner: 'either', isWritable: true, name: 'owner', }); test('mergeVisitor', () => { expectMergeVisitorCount(node, 2); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[instructionAccountNode]', null); expectDeleteNodesVisitor(node, '[accountValueNode]', instructionAccountNode({ ...node, defaultValue: undefined })); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` instructionAccountNode [owner.writable.optionalSigner] | accountValueNode [authority]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/InstructionArgumentNode.test.ts ================================================ import { instructionArgumentNode, numberTypeNode, numberValueNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from './_setup'; const node = instructionArgumentNode({ defaultValue: numberValueNode(1), name: 'amount', type: numberTypeNode('u64'), }); test('mergeVisitor', () => { expectMergeVisitorCount(node, 3); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[instructionArgumentNode]', null); expectDeleteNodesVisitor(node, '[numberTypeNode]', null); expectDeleteNodesVisitor( node, '[numberValueNode]', instructionArgumentNode({ name: 'amount', type: numberTypeNode('u64') }), ); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` instructionArgumentNode [amount] | numberTypeNode [u64] | numberValueNode [1]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/InstructionByteDeltaNode.test.ts ================================================ import { instructionByteDeltaNode, numberValueNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from './_setup'; const node = instructionByteDeltaNode(numberValueNode(42), { subtract: true, }); test('mergeVisitor', () => { expectMergeVisitorCount(node, 2); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[instructionByteDeltaNode]', null); expectDeleteNodesVisitor(node, '[numberValueNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` instructionByteDeltaNode [subtract.withHeader] | numberValueNode [42]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/InstructionNode.test.ts ================================================ import { fieldDiscriminatorNode, instructionAccountNode, instructionArgumentNode, instructionByteDeltaNode, instructionNode, instructionRemainingAccountsNode, instructionStatusNode, numberTypeNode, numberValueNode, publicKeyTypeNode, resolverValueNode, } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from './_setup'; const node = instructionNode({ accounts: [ instructionAccountNode({ isSigner: true, isWritable: true, name: 'source', }), instructionAccountNode({ isSigner: false, isWritable: true, name: 'destination', }), ], arguments: [ instructionArgumentNode({ name: 'discriminator', type: numberTypeNode('u32'), }), instructionArgumentNode({ name: 'amount', type: numberTypeNode('u64'), }), ], discriminators: [fieldDiscriminatorNode('discriminator')], name: 'transferSol', }); test('mergeVisitor', () => { expectMergeVisitorCount(node, 8); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[instructionNode]', null); expectDeleteNodesVisitor(node, '[instructionAccountNode]', { ...node, accounts: [] }); expectDeleteNodesVisitor(node, '[instructionArgumentNode]', { ...node, arguments: [] }); expectDeleteNodesVisitor(node, '[fieldDiscriminatorNode]', { ...node, discriminators: [] }); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` instructionNode [transferSol] | instructionAccountNode [source.writable.signer] | instructionAccountNode [destination.writable] | instructionArgumentNode [discriminator] | | numberTypeNode [u32] | instructionArgumentNode [amount] | | numberTypeNode [u64] | fieldDiscriminatorNode [discriminator]`, ); }); test('extra arguments', () => { const nodeWithExtraArguments = instructionNode({ extraArguments: [ instructionArgumentNode({ name: 'myExtraArgument', type: publicKeyTypeNode(), }), ], name: 'myInstruction', }); expectMergeVisitorCount(nodeWithExtraArguments, 3); expectIdentityVisitor(nodeWithExtraArguments); }); test('remaining accounts', () => { const nodeWithRemainingAccounts = instructionNode({ name: 'myInstruction', remainingAccounts: [instructionRemainingAccountsNode(resolverValueNode('myResolver'))], }); expectMergeVisitorCount(nodeWithRemainingAccounts, 3); expectIdentityVisitor(nodeWithRemainingAccounts); }); test('byte deltas', () => { const nodeWithByteDeltas = instructionNode({ byteDeltas: [instructionByteDeltaNode(numberValueNode(42))], name: 'myInstruction', }); expectMergeVisitorCount(nodeWithByteDeltas, 3); expectIdentityVisitor(nodeWithByteDeltas); }); test('sub instructions', () => { const nodeWithSubInstructions = instructionNode({ name: 'myInstruction', subInstructions: [ instructionNode({ name: 'mySubInstruction1' }), instructionNode({ name: 'mySubInstruction2' }), ], }); expectMergeVisitorCount(nodeWithSubInstructions, 3); expectIdentityVisitor(nodeWithSubInstructions); }); test('status mode', () => { const nodeWithStatus = instructionNode({ name: 'deprecatedInstruction', status: instructionStatusNode('deprecated', 'Use newInstruction instead'), }); expectMergeVisitorCount(nodeWithStatus, 2); expectIdentityVisitor(nodeWithStatus); expectDebugStringVisitor( nodeWithStatus, ` instructionNode [deprecatedInstruction] | instructionStatusNode [deprecated.Use newInstruction instead]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/InstructionRemainingAccountsNode.test.ts ================================================ import { argumentValueNode, instructionRemainingAccountsNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from './_setup'; const node = instructionRemainingAccountsNode(argumentValueNode('remainingAccounts'), { isSigner: 'either', isWritable: true, }); test('mergeVisitor', () => { expectMergeVisitorCount(node, 2); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[instructionRemainingAccountsNode]', null); expectDeleteNodesVisitor(node, '[argumentValueNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` instructionRemainingAccountsNode [writable.optionalSigner] | argumentValueNode [remainingAccounts]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/PdaNode.test.ts ================================================ import { constantPdaSeedNode, numberTypeNode, numberValueNode, pdaNode, publicKeyTypeNode, variablePdaSeedNode, } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from './_setup'; const node = pdaNode({ name: 'associatedToken', seeds: [ variablePdaSeedNode('owner', publicKeyTypeNode()), constantPdaSeedNode(numberTypeNode('u8'), numberValueNode(123456)), variablePdaSeedNode('mint', publicKeyTypeNode()), ], }); test('mergeVisitor', () => { expectMergeVisitorCount(node, 8); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[pdaNode]', null); expectDeleteNodesVisitor(node, ['[variablePdaSeedNode]', '[constantPdaSeedNode]'], { ...node, seeds: [] }); expectDeleteNodesVisitor(node, '[publicKeyTypeNode]', { ...node, seeds: [constantPdaSeedNode(numberTypeNode('u8'), numberValueNode(123456))], }); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` pdaNode [associatedToken] | variablePdaSeedNode [owner] | | publicKeyTypeNode | constantPdaSeedNode | | numberTypeNode [u8] | | numberValueNode [123456] | variablePdaSeedNode [mint] | | publicKeyTypeNode`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/ProgramNode.test.ts ================================================ import { accountNode, definedTypeNode, enumTypeNode, errorNode, eventNode, instructionNode, pdaNode, programNode, structTypeNode, } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from './_setup'; const node = programNode({ accounts: [ accountNode({ data: structTypeNode([]), name: 'mint' }), accountNode({ data: structTypeNode([]), name: 'token' }), ], definedTypes: [definedTypeNode({ name: 'tokenState', type: enumTypeNode([]) })], errors: [ errorNode({ code: 1, message: 'Invalid mint', name: 'invalidMint' }), errorNode({ code: 2, message: 'Invalid token', name: 'invalidToken' }), ], events: [eventNode({ data: structTypeNode([]), name: 'transferEvent' })], instructions: [instructionNode({ name: 'mintTokens' }), instructionNode({ name: 'transferTokens' })], name: 'splToken', pdas: [pdaNode({ name: 'associatedToken', seeds: [] })], publicKey: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', version: '1.2.3', }); test('mergeVisitor', () => { expectMergeVisitorCount(node, 15); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[programNode]', null); expectDeleteNodesVisitor(node, '[pdaNode]', { ...node, pdas: [] }); expectDeleteNodesVisitor(node, '[accountNode]', { ...node, accounts: [] }); expectDeleteNodesVisitor(node, '[eventNode]', { ...node, events: [] }); expectDeleteNodesVisitor(node, '[instructionNode]', { ...node, instructions: [] }); expectDeleteNodesVisitor(node, '[definedTypeNode]', { ...node, definedTypes: [] }); expectDeleteNodesVisitor(node, '[errorNode]', { ...node, errors: [] }); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` programNode [splToken.TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA] | pdaNode [associatedToken] | accountNode [mint] | | structTypeNode | accountNode [token] | | structTypeNode | eventNode [transferEvent] | | structTypeNode | instructionNode [mintTokens] | instructionNode [transferTokens] | definedTypeNode [tokenState] | | enumTypeNode | | | numberTypeNode [u8] | errorNode [1.invalidMint] | errorNode [2.invalidToken]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/RootNode.test.ts ================================================ import { programNode, rootNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from './_setup'; const node = rootNode( programNode({ name: 'splToken', publicKey: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', }), [ programNode({ name: 'splAddressLookupTable', publicKey: 'AddressLookupTab1e1111111111111111111111111', }), ], ); test('mergeVisitor', () => { expectMergeVisitorCount(node, 3); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[rootNode]', null); expectDeleteNodesVisitor(node, '[programNode]', null); expectDeleteNodesVisitor(node, '[programNode]splAddressLookupTable', { ...node, additionalPrograms: [] }); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` rootNode | programNode [splToken.TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA] | programNode [splAddressLookupTable.AddressLookupTab1e1111111111111111111111111]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/_setup.ts ================================================ import type { Node } from '@codama/nodes'; import { expect } from 'vitest'; import { deleteNodesVisitor, getDebugStringVisitor, identityVisitor, mergeVisitor, NodeSelector, visit, } from '../../src'; export const expectMergeVisitorCount = (node: Node, expectedNodeCount: number) => { const visitor = mergeVisitor( () => 1, (_, values) => values.reduce((a, b) => a + b, 1), ); const result = visit(node, visitor); expect(result).toBe(expectedNodeCount); }; export const expectIdentityVisitor = (node: Node) => { const visitor = identityVisitor(); const result = visit(node, visitor); expect(result).toEqual(node); expect(result).not.toBe(node); expect(Object.isFrozen(result)).toBe(true); }; export const expectDeleteNodesVisitor = ( node: Node, selector: NodeSelector | NodeSelector[], expectedResult: Node | null, ) => { const selectors = Array.isArray(selector) ? selector : [selector]; const visitor = deleteNodesVisitor(selectors); const result = visit(node, visitor); if (expectedResult === null) { expect(result).toBeNull(); } else { expect(result).toEqual(expectedResult); expect(result).not.toBe(expectedResult); expect(Object.isFrozen(result)).toBe(true); } }; export const expectDebugStringVisitor = (node: Node, expectedIndentedString: string) => { const visitor = getDebugStringVisitor({ indent: true }); const result = visit(node, visitor); expect(result).toBe(expectedIndentedString.trim()); }; ================================================ FILE: packages/visitors-core/test/nodes/contextualValueNodes/AccountBumpValueNode.test.ts ================================================ import { accountBumpValueNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = accountBumpValueNode('metadata'); test('mergeVisitor', () => { expectMergeVisitorCount(node, 1); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[accountBumpValueNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor(node, `accountBumpValueNode [metadata]`); }); ================================================ FILE: packages/visitors-core/test/nodes/contextualValueNodes/AccountValueNode.test.ts ================================================ import { accountValueNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = accountValueNode('mint'); test('mergeVisitor', () => { expectMergeVisitorCount(node, 1); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[accountValueNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor(node, `accountValueNode [mint]`); }); ================================================ FILE: packages/visitors-core/test/nodes/contextualValueNodes/ArgumentValueNode.test.ts ================================================ import { argumentValueNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = argumentValueNode('space'); test('mergeVisitor', () => { expectMergeVisitorCount(node, 1); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[argumentValueNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor(node, `argumentValueNode [space]`); }); ================================================ FILE: packages/visitors-core/test/nodes/contextualValueNodes/ConditionalValueNode.test.ts ================================================ import { accountValueNode, argumentValueNode, conditionalValueNode, enumValueNode, programIdValueNode, } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = conditionalValueNode({ condition: argumentValueNode('tokenStandard'), ifFalse: programIdValueNode(), ifTrue: accountValueNode('mint'), value: enumValueNode('tokenStandard', 'ProgrammableNonFungible'), }); test('mergeVisitor', () => { expectMergeVisitorCount(node, 6); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[conditionalValueNode]', null); expectDeleteNodesVisitor(node, '[enumValueNode]', conditionalValueNode({ ...node, value: undefined })); expectDeleteNodesVisitor(node, '[accountValueNode]', conditionalValueNode({ ...node, ifTrue: undefined })); expectDeleteNodesVisitor(node, '[programIdValueNode]', conditionalValueNode({ ...node, ifFalse: undefined })); expectDeleteNodesVisitor(node, ['[accountValueNode]', '[programIdValueNode]'], null); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` conditionalValueNode | argumentValueNode [tokenStandard] | enumValueNode [programmableNonFungible] | | definedTypeLinkNode [tokenStandard] | accountValueNode [mint] | programIdValueNode`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/contextualValueNodes/IdentityValueNode.test.ts ================================================ import { identityValueNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = identityValueNode(); test('mergeVisitor', () => { expectMergeVisitorCount(node, 1); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[identityValueNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor(node, `identityValueNode`); }); ================================================ FILE: packages/visitors-core/test/nodes/contextualValueNodes/PayerValueNode.test.ts ================================================ import { payerValueNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = payerValueNode(); test('mergeVisitor', () => { expectMergeVisitorCount(node, 1); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[payerValueNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor(node, `payerValueNode`); }); ================================================ FILE: packages/visitors-core/test/nodes/contextualValueNodes/PdaSeedValueNode.test.ts ================================================ import { accountValueNode, pdaSeedValueNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = pdaSeedValueNode('mint', accountValueNode('mint')); test('mergeVisitor', () => { expectMergeVisitorCount(node, 2); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[pdaSeedValueNode]', null); expectDeleteNodesVisitor(node, '[accountValueNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` pdaSeedValueNode [mint] | accountValueNode [mint]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/contextualValueNodes/PdaValueNode.test.ts ================================================ import { accountValueNode, constantPdaSeedNode, pdaLinkNode, pdaNode, pdaSeedValueNode, pdaValueNode, publicKeyTypeNode, publicKeyValueNode, variablePdaSeedNode, } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = pdaValueNode(pdaLinkNode('associatedToken'), [ pdaSeedValueNode('mint', accountValueNode('mint')), pdaSeedValueNode('owner', publicKeyValueNode('8sphVBHQxufE4Jc1HMuWwWdKgoDjncQyPHwxYhfATRtF')), ]); test('mergeVisitor', () => { expectMergeVisitorCount(node, 6); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('identityVisitor with inlined PdaNode', () => { const inlinedPdaNode = pdaNode({ name: 'associatedToken', seeds: [ variablePdaSeedNode('mint', publicKeyTypeNode()), constantPdaSeedNode( publicKeyTypeNode(), publicKeyValueNode('ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL'), ), variablePdaSeedNode('owner', publicKeyTypeNode()), ], }); const inlinedPdaValueNode = pdaValueNode(inlinedPdaNode, [ pdaSeedValueNode('mint', accountValueNode('mint')), pdaSeedValueNode('owner', publicKeyValueNode('8sphVBHQxufE4Jc1HMuWwWdKgoDjncQyPHwxYhfATRtF')), ]); expectIdentityVisitor(inlinedPdaValueNode); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[pdaValueNode]', null); expectDeleteNodesVisitor(node, '[pdaLinkNode]', null); expectDeleteNodesVisitor(node, '[pdaSeedValueNode]', { ...node, seeds: [] }); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` pdaValueNode | pdaLinkNode [associatedToken] | pdaSeedValueNode [mint] | | accountValueNode [mint] | pdaSeedValueNode [owner] | | publicKeyValueNode [8sphVBHQxufE4Jc1HMuWwWdKgoDjncQyPHwxYhfATRtF]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/contextualValueNodes/ProgramIdValueNode.test.ts ================================================ import { programIdValueNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = programIdValueNode(); test('mergeVisitor', () => { expectMergeVisitorCount(node, 1); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[programIdValueNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor(node, `programIdValueNode`); }); ================================================ FILE: packages/visitors-core/test/nodes/contextualValueNodes/ResolverValueNode.test.ts ================================================ import { accountValueNode, argumentValueNode, resolverValueNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = resolverValueNode('myCustomResolver', { dependsOn: [accountValueNode('mint'), argumentValueNode('tokenStandard')], }); test('mergeVisitor', () => { expectMergeVisitorCount(node, 3); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[resolverValueNode]', null); expectDeleteNodesVisitor(node, ['[accountValueNode]', '[argumentValueNode]'], { ...node, dependsOn: undefined }); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` resolverValueNode [myCustomResolver] | accountValueNode [mint] | argumentValueNode [tokenStandard]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/discriminatorNodes/ConstantDiscriminatorNode.test.ts ================================================ import { constantDiscriminatorNode, constantValueNodeFromBytes } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = constantDiscriminatorNode(constantValueNodeFromBytes('base16', '01020304'), 42); test('mergeVisitor', () => { expectMergeVisitorCount(node, 4); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[constantDiscriminatorNode]', null); expectDeleteNodesVisitor(node, '[constantValueNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` constantDiscriminatorNode [offset:42] | constantValueNode | | bytesTypeNode | | bytesValueNode [base16.01020304]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/discriminatorNodes/FieldDiscriminatorNode.test.ts ================================================ import { fieldDiscriminatorNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = fieldDiscriminatorNode('discriminator', 42); test('mergeVisitor', () => { expectMergeVisitorCount(node, 1); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[fieldDiscriminatorNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor(node, `fieldDiscriminatorNode [discriminator.offset:42]`); }); ================================================ FILE: packages/visitors-core/test/nodes/discriminatorNodes/SizeDiscriminatorNode.test.ts ================================================ import { sizeDiscriminatorNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = sizeDiscriminatorNode(42); test('mergeVisitor', () => { expectMergeVisitorCount(node, 1); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[sizeDiscriminatorNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor(node, `sizeDiscriminatorNode [42]`); }); ================================================ FILE: packages/visitors-core/test/nodes/linkNodes/AccountLinkNode.test.ts ================================================ import { accountLinkNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = accountLinkNode('token', 'splToken'); test('mergeVisitor', () => { expectMergeVisitorCount(node, 2); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[accountLinkNode]', null); expectDeleteNodesVisitor(node, '[programLinkNode]', accountLinkNode('token')); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` accountLinkNode [token] | programLinkNode [splToken]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/linkNodes/DefinedTypeLinkNode.test.ts ================================================ import { definedTypeLinkNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = definedTypeLinkNode('tokenState', 'splToken'); test('mergeVisitor', () => { expectMergeVisitorCount(node, 2); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[definedTypeLinkNode]', null); expectDeleteNodesVisitor(node, '[programLinkNode]', definedTypeLinkNode('tokenState')); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` definedTypeLinkNode [tokenState] | programLinkNode [splToken]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/linkNodes/InstructionAccountLinkNode.test.ts ================================================ import { instructionAccountLinkNode, instructionLinkNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = instructionAccountLinkNode('mint', instructionLinkNode('transferTokens', 'splToken')); test('mergeVisitor', () => { expectMergeVisitorCount(node, 3); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[instructionAccountLinkNode]', null); expectDeleteNodesVisitor(node, '[instructionLinkNode]', instructionAccountLinkNode('mint')); expectDeleteNodesVisitor(node, '[programLinkNode]', instructionAccountLinkNode('mint', 'transferTokens')); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` instructionAccountLinkNode [mint] | instructionLinkNode [transferTokens] | | programLinkNode [splToken]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/linkNodes/InstructionArgumentLinkNode.test.ts ================================================ import { instructionArgumentLinkNode, instructionLinkNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = instructionArgumentLinkNode('amount', instructionLinkNode('transferTokens', 'splToken')); test('mergeVisitor', () => { expectMergeVisitorCount(node, 3); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[instructionArgumentLinkNode]', null); expectDeleteNodesVisitor(node, '[instructionLinkNode]', instructionArgumentLinkNode('amount')); expectDeleteNodesVisitor(node, '[programLinkNode]', instructionArgumentLinkNode('amount', 'transferTokens')); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` instructionArgumentLinkNode [amount] | instructionLinkNode [transferTokens] | | programLinkNode [splToken]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/linkNodes/InstructionLinkNode.test.ts ================================================ import { instructionLinkNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = instructionLinkNode('transferTokens', 'splToken'); test('mergeVisitor', () => { expectMergeVisitorCount(node, 2); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[instructionLinkNode]', null); expectDeleteNodesVisitor(node, '[programLinkNode]', instructionLinkNode('transferTokens')); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` instructionLinkNode [transferTokens] | programLinkNode [splToken]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/linkNodes/PdaLinkNode.test.ts ================================================ import { pdaLinkNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = pdaLinkNode('associatedToken', 'splToken'); test('mergeVisitor', () => { expectMergeVisitorCount(node, 2); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[pdaLinkNode]', null); expectDeleteNodesVisitor(node, '[programLinkNode]', pdaLinkNode('associatedToken')); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` pdaLinkNode [associatedToken] | programLinkNode [splToken]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/linkNodes/ProgramLinkNode.test.ts ================================================ import { programLinkNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = programLinkNode('mplCandyGuard'); test('mergeVisitor', () => { expectMergeVisitorCount(node, 1); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[programLinkNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor(node, `programLinkNode [mplCandyGuard]`); }); ================================================ FILE: packages/visitors-core/test/nodes/pdaSeedNodes/ConstantPdaSeedNode.test.ts ================================================ import { constantPdaSeedNode, numberTypeNode, numberValueNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = constantPdaSeedNode(numberTypeNode('u8'), numberValueNode(42)); test('mergeVisitor', () => { expectMergeVisitorCount(node, 3); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[constantPdaSeedNode]', null); expectDeleteNodesVisitor(node, '[numberTypeNode]', null); expectDeleteNodesVisitor(node, '[numberValueNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` constantPdaSeedNode | numberTypeNode [u8] | numberValueNode [42]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/pdaSeedNodes/VariablePdaSeedNode.test.ts ================================================ import { publicKeyTypeNode, variablePdaSeedNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = variablePdaSeedNode('mint', publicKeyTypeNode()); test('mergeVisitor', () => { expectMergeVisitorCount(node, 2); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[variablePdaSeedNode]', null); expectDeleteNodesVisitor(node, '[publicKeyTypeNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` variablePdaSeedNode [mint] | publicKeyTypeNode`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/sizeNodes/FixedSizeNode.test.ts ================================================ import { fixedCountNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = fixedCountNode(42); test('mergeVisitor', () => { expectMergeVisitorCount(node, 1); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[fixedCountNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor(node, `fixedCountNode [42]`); }); ================================================ FILE: packages/visitors-core/test/nodes/sizeNodes/PrefixedSizeNode.test.ts ================================================ import { numberTypeNode, prefixedCountNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = prefixedCountNode(numberTypeNode('u64')); test('mergeVisitor', () => { expectMergeVisitorCount(node, 2); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[prefixedCountNode]', null); expectDeleteNodesVisitor(node, '[numberTypeNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` prefixedCountNode | numberTypeNode [u64]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/sizeNodes/RemainderSizeNode.test.ts ================================================ import { remainderCountNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = remainderCountNode(); test('mergeVisitor', () => { expectMergeVisitorCount(node, 1); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[remainderCountNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor(node, `remainderCountNode`); }); ================================================ FILE: packages/visitors-core/test/nodes/typeNodes/AmountTypeNode.test.ts ================================================ import { amountTypeNode, numberTypeNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = amountTypeNode(numberTypeNode('u64'), 9, 'SOL'); test('mergeVisitor', () => { expectMergeVisitorCount(node, 2); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[amountTypeNode]', null); expectDeleteNodesVisitor(node, '[numberTypeNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` amountTypeNode [9.SOL] | numberTypeNode [u64]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/typeNodes/ArrayTypeNode.test.ts ================================================ import { arrayTypeNode, numberTypeNode, prefixedCountNode, publicKeyTypeNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = arrayTypeNode(publicKeyTypeNode(), prefixedCountNode(numberTypeNode('u64'))); test('mergeVisitor', () => { expectMergeVisitorCount(node, 4); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[arrayTypeNode]', null); expectDeleteNodesVisitor(node, '[publicKeyTypeNode]', null); expectDeleteNodesVisitor(node, '[prefixedCountNode]', null); expectDeleteNodesVisitor(node, '[numberTypeNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` arrayTypeNode | prefixedCountNode | | numberTypeNode [u64] | publicKeyTypeNode`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/typeNodes/BooleanTypeNode.test.ts ================================================ import { booleanTypeNode, numberTypeNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = booleanTypeNode(numberTypeNode('u32')); test('mergeVisitor', () => { expectMergeVisitorCount(node, 2); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[booleanTypeNode]', null); expectDeleteNodesVisitor(node, '[numberTypeNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` booleanTypeNode | numberTypeNode [u32]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/typeNodes/BytesTypeNode.test.ts ================================================ import { bytesTypeNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = bytesTypeNode(); test('mergeVisitor', () => { expectMergeVisitorCount(node, 1); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[bytesTypeNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor(node, `bytesTypeNode`); }); ================================================ FILE: packages/visitors-core/test/nodes/typeNodes/DateTimeTypeNode.test.ts ================================================ import { dateTimeTypeNode, numberTypeNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = dateTimeTypeNode(numberTypeNode('u64')); test('mergeVisitor', () => { expectMergeVisitorCount(node, 2); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[dateTimeTypeNode]', null); expectDeleteNodesVisitor(node, '[numberTypeNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` dateTimeTypeNode | numberTypeNode [u64]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/typeNodes/EnumEmptyVariantTypeNode.test.ts ================================================ import { enumEmptyVariantTypeNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = enumEmptyVariantTypeNode('initialized'); test('mergeVisitor', () => { expectMergeVisitorCount(node, 1); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[enumEmptyVariantTypeNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor(node, `enumEmptyVariantTypeNode [initialized]`); }); ================================================ FILE: packages/visitors-core/test/nodes/typeNodes/EnumStructVariantTypeNode.test.ts ================================================ import { enumEmptyVariantTypeNode, enumStructVariantTypeNode, numberTypeNode, structFieldTypeNode, structTypeNode, } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = enumStructVariantTypeNode( 'mouseClick', structTypeNode([ structFieldTypeNode({ name: 'x', type: numberTypeNode('u32') }), structFieldTypeNode({ name: 'y', type: numberTypeNode('u32') }), ]), ); test('mergeVisitor', () => { expectMergeVisitorCount(node, 6); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[enumStructVariantTypeNode]', null); expectDeleteNodesVisitor(node, '[structTypeNode]', enumEmptyVariantTypeNode('mouseClick')); expectDeleteNodesVisitor(node, '[structFieldTypeNode]', enumEmptyVariantTypeNode('mouseClick')); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` enumStructVariantTypeNode [mouseClick] | structTypeNode | | structFieldTypeNode [x] | | | numberTypeNode [u32] | | structFieldTypeNode [y] | | | numberTypeNode [u32]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/typeNodes/EnumTupleVariantTypeNode.test.ts ================================================ import { enumEmptyVariantTypeNode, enumTupleVariantTypeNode, numberTypeNode, tupleTypeNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = enumTupleVariantTypeNode('coordinates', tupleTypeNode([numberTypeNode('u32'), numberTypeNode('u32')])); test('mergeVisitor', () => { expectMergeVisitorCount(node, 4); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[enumTupleVariantTypeNode]', null); expectDeleteNodesVisitor(node, '[tupleTypeNode]', enumEmptyVariantTypeNode('coordinates')); expectDeleteNodesVisitor(node, '[numberTypeNode]', enumEmptyVariantTypeNode('coordinates')); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` enumTupleVariantTypeNode [coordinates] | tupleTypeNode | | numberTypeNode [u32] | | numberTypeNode [u32]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/typeNodes/EnumTypeNode.test.ts ================================================ import { enumEmptyVariantTypeNode, enumStructVariantTypeNode, enumTupleVariantTypeNode, enumTypeNode, fixedSizeTypeNode, numberTypeNode, stringTypeNode, structFieldTypeNode, structTypeNode, tupleTypeNode, } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = enumTypeNode( [ enumEmptyVariantTypeNode('quit'), enumTupleVariantTypeNode('write', tupleTypeNode([fixedSizeTypeNode(stringTypeNode('utf8'), 32)])), enumStructVariantTypeNode( 'move', structTypeNode([ structFieldTypeNode({ name: 'x', type: numberTypeNode('u32') }), structFieldTypeNode({ name: 'y', type: numberTypeNode('u32') }), ]), ), ], { size: numberTypeNode('u64') }, ); test('mergeVisitor', () => { expectMergeVisitorCount(node, 13); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[enumTypeNode]', null); expectDeleteNodesVisitor( node, ['[enumEmptyVariantTypeNode]', '[enumTupleVariantTypeNode]', '[enumStructVariantTypeNode]'], { ...node, variants: [] }, ); expectDeleteNodesVisitor(node, ['[tupleTypeNode]', '[structFieldTypeNode]'], { ...node, variants: [ enumEmptyVariantTypeNode('quit'), enumEmptyVariantTypeNode('write'), enumEmptyVariantTypeNode('move'), ], }); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` enumTypeNode | numberTypeNode [u64] | enumEmptyVariantTypeNode [quit] | enumTupleVariantTypeNode [write] | | tupleTypeNode | | | fixedSizeTypeNode [32] | | | | stringTypeNode [utf8] | enumStructVariantTypeNode [move] | | structTypeNode | | | structFieldTypeNode [x] | | | | numberTypeNode [u32] | | | structFieldTypeNode [y] | | | | numberTypeNode [u32]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/typeNodes/FixedSizeTypeNode.test.ts ================================================ import { fixedSizeTypeNode, stringTypeNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = fixedSizeTypeNode(stringTypeNode('utf8'), 42); test('mergeVisitor', () => { expectMergeVisitorCount(node, 2); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[fixedSizeTypeNode]', null); expectDeleteNodesVisitor(node, '[stringTypeNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` fixedSizeTypeNode [42] | stringTypeNode [utf8]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/typeNodes/HiddenPrefixTypeNode.test.ts ================================================ import { constantValueNodeFromBytes, constantValueNodeFromString, hiddenPrefixTypeNode, numberTypeNode, } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = hiddenPrefixTypeNode(numberTypeNode('u32'), [ constantValueNodeFromString('utf8', 'hello world'), constantValueNodeFromBytes('base16', 'ffff'), ]); test('mergeVisitor', () => { expectMergeVisitorCount(node, 8); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[hiddenPrefixTypeNode]', null); expectDeleteNodesVisitor(node, '[numberTypeNode]', null); expectDeleteNodesVisitor(node, '[constantValueNode]', numberTypeNode('u32')); expectDeleteNodesVisitor( node, '[stringTypeNode]', hiddenPrefixTypeNode(numberTypeNode('u32'), [constantValueNodeFromBytes('base16', 'ffff')]), ); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` hiddenPrefixTypeNode | constantValueNode | | stringTypeNode [utf8] | | stringValueNode [hello world] | constantValueNode | | bytesTypeNode | | bytesValueNode [base16.ffff] | numberTypeNode [u32]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/typeNodes/HiddenSuffixTypeNode.test.ts ================================================ import { constantValueNodeFromBytes, constantValueNodeFromString, hiddenSuffixTypeNode, numberTypeNode, } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = hiddenSuffixTypeNode(numberTypeNode('u32'), [ constantValueNodeFromString('utf8', 'hello world'), constantValueNodeFromBytes('base16', 'ffff'), ]); test('mergeVisitor', () => { expectMergeVisitorCount(node, 8); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[hiddenSuffixTypeNode]', null); expectDeleteNodesVisitor(node, '[numberTypeNode]', null); expectDeleteNodesVisitor(node, '[constantValueNode]', numberTypeNode('u32')); expectDeleteNodesVisitor( node, '[stringTypeNode]', hiddenSuffixTypeNode(numberTypeNode('u32'), [constantValueNodeFromBytes('base16', 'ffff')]), ); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` hiddenSuffixTypeNode | numberTypeNode [u32] | constantValueNode | | stringTypeNode [utf8] | | stringValueNode [hello world] | constantValueNode | | bytesTypeNode | | bytesValueNode [base16.ffff]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/typeNodes/MapTypeNode.test.ts ================================================ import { fixedSizeTypeNode, mapTypeNode, numberTypeNode, prefixedCountNode, publicKeyTypeNode, stringTypeNode, } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = mapTypeNode( fixedSizeTypeNode(stringTypeNode('utf8'), 32), publicKeyTypeNode(), prefixedCountNode(numberTypeNode('u8')), ); test('mergeVisitor', () => { expectMergeVisitorCount(node, 6); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[mapTypeNode]', null); expectDeleteNodesVisitor(node, '[stringTypeNode]', null); expectDeleteNodesVisitor(node, '[publicKeyTypeNode]', null); expectDeleteNodesVisitor(node, '[prefixedCountNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` mapTypeNode | prefixedCountNode | | numberTypeNode [u8] | fixedSizeTypeNode [32] | | stringTypeNode [utf8] | publicKeyTypeNode`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/typeNodes/NumberTypeNode.test.ts ================================================ import { numberTypeNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = numberTypeNode('f64'); test('mergeVisitor', () => { expectMergeVisitorCount(node, 1); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[numberTypeNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor(node, `numberTypeNode [f64]`); expectDebugStringVisitor(numberTypeNode('f64', 'be'), `numberTypeNode [f64.bigEndian]`); }); ================================================ FILE: packages/visitors-core/test/nodes/typeNodes/OptionTypeNode.test.ts ================================================ import { numberTypeNode, optionTypeNode, publicKeyTypeNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = optionTypeNode(publicKeyTypeNode(), { fixed: true, prefix: numberTypeNode('u64'), }); test('mergeVisitor', () => { expectMergeVisitorCount(node, 3); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[optionTypeNode]', null); expectDeleteNodesVisitor(node, '[publicKeyTypeNode]', null); expectDeleteNodesVisitor(node, '[numberTypeNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` optionTypeNode [fixed] | numberTypeNode [u64] | publicKeyTypeNode`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/typeNodes/PostOffsetTypeNode.test.ts ================================================ import { postOffsetTypeNode, stringTypeNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = postOffsetTypeNode(stringTypeNode('utf8'), 42); test('mergeVisitor', () => { expectMergeVisitorCount(node, 2); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[stringTypeNode]', null); expectDeleteNodesVisitor(node, '[postOffsetTypeNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` postOffsetTypeNode [42.relative] | stringTypeNode [utf8]`, ); expectDebugStringVisitor( postOffsetTypeNode(stringTypeNode('utf8'), 42, 'absolute'), ` postOffsetTypeNode [42.absolute] | stringTypeNode [utf8]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/typeNodes/PreOffsetTypeNode.test.ts ================================================ import { preOffsetTypeNode, stringTypeNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = preOffsetTypeNode(stringTypeNode('utf8'), 42); test('mergeVisitor', () => { expectMergeVisitorCount(node, 2); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[stringTypeNode]', null); expectDeleteNodesVisitor(node, '[preOffsetTypeNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` preOffsetTypeNode [42.relative] | stringTypeNode [utf8]`, ); expectDebugStringVisitor( preOffsetTypeNode(stringTypeNode('utf8'), 42, 'absolute'), ` preOffsetTypeNode [42.absolute] | stringTypeNode [utf8]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/typeNodes/PublicKeyTypeNode.test.ts ================================================ import { publicKeyTypeNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = publicKeyTypeNode(); test('mergeVisitor', () => { expectMergeVisitorCount(node, 1); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[publicKeyTypeNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor(node, `publicKeyTypeNode`); }); ================================================ FILE: packages/visitors-core/test/nodes/typeNodes/RemainderOptionTypeNode.test.ts ================================================ import { publicKeyTypeNode, remainderOptionTypeNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = remainderOptionTypeNode(publicKeyTypeNode()); test('mergeVisitor', () => { expectMergeVisitorCount(node, 2); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[remainderOptionTypeNode]', null); expectDeleteNodesVisitor(node, '[publicKeyTypeNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` remainderOptionTypeNode | publicKeyTypeNode`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/typeNodes/SentinelTypeNode.test.ts ================================================ import { constantValueNodeFromBytes, sentinelTypeNode, stringTypeNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = sentinelTypeNode(stringTypeNode('utf8'), constantValueNodeFromBytes('base16', 'ffff')); test('mergeVisitor', () => { expectMergeVisitorCount(node, 5); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[sentinelTypeNode]', null); expectDeleteNodesVisitor(node, '[stringTypeNode]', null); expectDeleteNodesVisitor(node, '[constantValueNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` sentinelTypeNode | constantValueNode | | bytesTypeNode | | bytesValueNode [base16.ffff] | stringTypeNode [utf8]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/typeNodes/SetTypeNode.test.ts ================================================ import { publicKeyTypeNode, remainderCountNode, setTypeNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = setTypeNode(publicKeyTypeNode(), remainderCountNode()); test('mergeVisitor', () => { expectMergeVisitorCount(node, 3); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[setTypeNode]', null); expectDeleteNodesVisitor(node, '[publicKeyTypeNode]', null); expectDeleteNodesVisitor(node, '[remainderCountNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` setTypeNode | remainderCountNode | publicKeyTypeNode`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/typeNodes/SizePrefixTypeNode.test.ts ================================================ import { numberTypeNode, sizePrefixTypeNode, stringTypeNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = sizePrefixTypeNode(stringTypeNode('utf8'), numberTypeNode('u32')); test('mergeVisitor', () => { expectMergeVisitorCount(node, 3); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[sizePrefixTypeNode]', null); expectDeleteNodesVisitor(node, '[stringTypeNode]', null); expectDeleteNodesVisitor(node, '[numberTypeNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` sizePrefixTypeNode | numberTypeNode [u32] | stringTypeNode [utf8]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/typeNodes/SolAmountTypeNode.test.ts ================================================ import { numberTypeNode, solAmountTypeNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = solAmountTypeNode(numberTypeNode('u64')); test('mergeVisitor', () => { expectMergeVisitorCount(node, 2); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[solAmountTypeNode]', null); expectDeleteNodesVisitor(node, '[numberTypeNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` solAmountTypeNode | numberTypeNode [u64]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/typeNodes/StringTypeNode.test.ts ================================================ import { stringTypeNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = stringTypeNode('utf8'); test('mergeVisitor', () => { expectMergeVisitorCount(node, 1); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[stringTypeNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor(node, `stringTypeNode [utf8]`); expectDebugStringVisitor(stringTypeNode('base58'), `stringTypeNode [base58]`); }); ================================================ FILE: packages/visitors-core/test/nodes/typeNodes/StructFieldTypeNode.test.ts ================================================ import { publicKeyTypeNode, publicKeyValueNode, structFieldTypeNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = structFieldTypeNode({ defaultValue: publicKeyValueNode('CzC5HidG6kR5J4haV7pKZmenYYVS7rw3SoBkqeStxZ9U'), name: 'owner', type: publicKeyTypeNode(), }); test('mergeVisitor', () => { expectMergeVisitorCount(node, 3); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[structFieldTypeNode]', null); expectDeleteNodesVisitor(node, '[publicKeyTypeNode]', null); expectDeleteNodesVisitor(node, '[publicKeyValueNode]', structFieldTypeNode({ ...node, defaultValue: undefined })); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` structFieldTypeNode [owner] | publicKeyTypeNode | publicKeyValueNode [CzC5HidG6kR5J4haV7pKZmenYYVS7rw3SoBkqeStxZ9U]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/typeNodes/StructTypeNode.test.ts ================================================ import { numberTypeNode, publicKeyTypeNode, structFieldTypeNode, structTypeNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = structTypeNode([ structFieldTypeNode({ name: 'owner', type: publicKeyTypeNode() }), structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64') }), ]); test('mergeVisitor', () => { expectMergeVisitorCount(node, 5); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[structTypeNode]', null); expectDeleteNodesVisitor(node, '[structFieldTypeNode]', { ...node, fields: [] }); expectDeleteNodesVisitor(node, ['[publicKeyTypeNode]', '[numberTypeNode]'], { ...node, fields: [] }); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` structTypeNode | structFieldTypeNode [owner] | | publicKeyTypeNode | structFieldTypeNode [amount] | | numberTypeNode [u64]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/typeNodes/TupleTypeNode.test.ts ================================================ import { numberTypeNode, publicKeyTypeNode, tupleTypeNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = tupleTypeNode([publicKeyTypeNode(), numberTypeNode('u64')]); test('mergeVisitor', () => { expectMergeVisitorCount(node, 3); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[tupleTypeNode]', null); expectDeleteNodesVisitor(node, ['[publicKeyTypeNode]', '[numberTypeNode]'], { ...node, items: [] }); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` tupleTypeNode | publicKeyTypeNode | numberTypeNode [u64]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/typeNodes/ZeroableOptionTypeNode.test.ts ================================================ import { constantValueNodeFromBytes, publicKeyTypeNode, zeroableOptionTypeNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = zeroableOptionTypeNode(publicKeyTypeNode(), constantValueNodeFromBytes('base16', 'ff'.repeat(32))); test('mergeVisitor', () => { expectMergeVisitorCount(node, 5); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[zeroableOptionTypeNode]', null); expectDeleteNodesVisitor(node, '[publicKeyTypeNode]', null); expectDeleteNodesVisitor(node, '[constantValueNode]', zeroableOptionTypeNode(publicKeyTypeNode())); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` zeroableOptionTypeNode | publicKeyTypeNode | constantValueNode | | bytesTypeNode | | bytesValueNode [base16.ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff]`, ); expectDebugStringVisitor( zeroableOptionTypeNode(publicKeyTypeNode()), ` zeroableOptionTypeNode | publicKeyTypeNode`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/valueNodes/ArrayValueNode.test.ts ================================================ import { arrayValueNode, publicKeyValueNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = arrayValueNode([ publicKeyValueNode('8jeCDm1zPb68kfzv5MaUo9BK7beGzFrGHA9hhMGL1ay1'), publicKeyValueNode('8PEBfDem8yb5aUkrhKgNKMraB9gR8WtJDprEW3QwLFz'), publicKeyValueNode('97hChLjFswwqBrE82Q4wqctpFfB2jZ91svxCv68iCrqG'), ]); test('mergeVisitor', () => { expectMergeVisitorCount(node, 4); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[arrayValueNode]', null); expectDeleteNodesVisitor(node, '[publicKeyValueNode]', { ...node, items: [] }); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` arrayValueNode | publicKeyValueNode [8jeCDm1zPb68kfzv5MaUo9BK7beGzFrGHA9hhMGL1ay1] | publicKeyValueNode [8PEBfDem8yb5aUkrhKgNKMraB9gR8WtJDprEW3QwLFz] | publicKeyValueNode [97hChLjFswwqBrE82Q4wqctpFfB2jZ91svxCv68iCrqG]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/valueNodes/BooleanValueNode.test.ts ================================================ import { booleanValueNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = booleanValueNode(true); test('mergeVisitor', () => { expectMergeVisitorCount(node, 1); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[booleanValueNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor(node, `booleanValueNode [true]`); }); ================================================ FILE: packages/visitors-core/test/nodes/valueNodes/BytesValueNode.test.ts ================================================ import { bytesValueNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = bytesValueNode('base64', 'SGVsbG8gV29ybGQ='); test('mergeVisitor', () => { expectMergeVisitorCount(node, 1); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[bytesValueNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor(node, `bytesValueNode [base64.SGVsbG8gV29ybGQ=]`); }); ================================================ FILE: packages/visitors-core/test/nodes/valueNodes/ConstantValueNode.test.ts ================================================ import { constantValueNode, numberTypeNode, numberValueNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = constantValueNode(numberTypeNode('u8'), numberValueNode(42)); test('mergeVisitor', () => { expectMergeVisitorCount(node, 3); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[constantValueNode]', null); expectDeleteNodesVisitor(node, '[numberTypeNode]', null); expectDeleteNodesVisitor(node, '[numberValueNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` constantValueNode | numberTypeNode [u8] | numberValueNode [42]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/valueNodes/EnumValueNode.test.ts ================================================ import { definedTypeLinkNode, enumValueNode, numberValueNode, stringValueNode, structFieldValueNode, structValueNode, } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = enumValueNode( definedTypeLinkNode('entity'), 'person', structValueNode([ structFieldValueNode('name', stringValueNode('Alice')), structFieldValueNode('age', numberValueNode(42)), ]), ); test('mergeVisitor', () => { expectMergeVisitorCount(node, 7); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[enumValueNode]', null); expectDeleteNodesVisitor(node, '[definedTypeLinkNode]', null); expectDeleteNodesVisitor(node, '[structValueNode]', enumValueNode(node.enum, node.variant)); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` enumValueNode [person] | definedTypeLinkNode [entity] | structValueNode | | structFieldValueNode [name] | | | stringValueNode [Alice] | | structFieldValueNode [age] | | | numberValueNode [42]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/valueNodes/MapEntryValueNode.test.ts ================================================ import { mapEntryValueNode, publicKeyValueNode, stringValueNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = mapEntryValueNode( stringValueNode('Alice'), publicKeyValueNode('GaxDPeNfXXgtwJXwHiDYVSDiM53RchFSRFTn2z2Jztuw'), ); test('mergeVisitor', () => { expectMergeVisitorCount(node, 3); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[mapEntryValueNode]', null); expectDeleteNodesVisitor(node, '[stringValueNode]', null); expectDeleteNodesVisitor(node, '[publicKeyValueNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` mapEntryValueNode | stringValueNode [Alice] | publicKeyValueNode [GaxDPeNfXXgtwJXwHiDYVSDiM53RchFSRFTn2z2Jztuw]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/valueNodes/MapValueNode.test.ts ================================================ import { mapEntryValueNode, mapValueNode, numberValueNode, stringValueNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = mapValueNode([ mapEntryValueNode(stringValueNode('Alice'), numberValueNode(42)), mapEntryValueNode(stringValueNode('Bob'), numberValueNode(37)), mapEntryValueNode(stringValueNode('Carla'), numberValueNode(29)), ]); test('mergeVisitor', () => { expectMergeVisitorCount(node, 10); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[mapValueNode]', null); expectDeleteNodesVisitor(node, '[mapEntryValueNode]', { ...node, entries: [] }); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` mapValueNode | mapEntryValueNode | | stringValueNode [Alice] | | numberValueNode [42] | mapEntryValueNode | | stringValueNode [Bob] | | numberValueNode [37] | mapEntryValueNode | | stringValueNode [Carla] | | numberValueNode [29]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/valueNodes/NoneValueNode.test.ts ================================================ import { noneValueNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = noneValueNode(); test('mergeVisitor', () => { expectMergeVisitorCount(node, 1); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[noneValueNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor(node, `noneValueNode`); }); ================================================ FILE: packages/visitors-core/test/nodes/valueNodes/NumberValueNode.test.ts ================================================ import { numberValueNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = numberValueNode(42); test('mergeVisitor', () => { expectMergeVisitorCount(node, 1); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[numberValueNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor(node, `numberValueNode [42]`); }); ================================================ FILE: packages/visitors-core/test/nodes/valueNodes/PublicKeyValueNode.test.ts ================================================ import { publicKeyValueNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = publicKeyValueNode('HqJgWgvkn5wMGU8LpzkRw8389N5Suvu2nZcmpya9JyJB'); test('mergeVisitor', () => { expectMergeVisitorCount(node, 1); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[publicKeyValueNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor(node, `publicKeyValueNode [HqJgWgvkn5wMGU8LpzkRw8389N5Suvu2nZcmpya9JyJB]`); expectDebugStringVisitor( publicKeyValueNode('HqJgWgvkn5wMGU8LpzkRw8389N5Suvu2nZcmpya9JyJB', 'myIdentifier'), `publicKeyValueNode [myIdentifier.HqJgWgvkn5wMGU8LpzkRw8389N5Suvu2nZcmpya9JyJB]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/valueNodes/SetValueNode.test.ts ================================================ import { publicKeyValueNode, setValueNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = setValueNode([ publicKeyValueNode('8jeCDm1zPb68kfzv5MaUo9BK7beGzFrGHA9hhMGL1ay1'), publicKeyValueNode('8PEBfDem8yb5aUkrhKgNKMraB9gR8WtJDprEW3QwLFz'), publicKeyValueNode('97hChLjFswwqBrE82Q4wqctpFfB2jZ91svxCv68iCrqG'), ]); test('mergeVisitor', () => { expectMergeVisitorCount(node, 4); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[setValueNode]', null); expectDeleteNodesVisitor(node, '[publicKeyValueNode]', { ...node, items: [] }); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` setValueNode | publicKeyValueNode [8jeCDm1zPb68kfzv5MaUo9BK7beGzFrGHA9hhMGL1ay1] | publicKeyValueNode [8PEBfDem8yb5aUkrhKgNKMraB9gR8WtJDprEW3QwLFz] | publicKeyValueNode [97hChLjFswwqBrE82Q4wqctpFfB2jZ91svxCv68iCrqG]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/valueNodes/SomeValueNode.test.ts ================================================ import { publicKeyValueNode, someValueNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = someValueNode(publicKeyValueNode('73na6yX22Xw3w7q3z39MAwtZyQehEMnUQceszCt94GJ3')); test('mergeVisitor', () => { expectMergeVisitorCount(node, 2); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[someValueNode]', null); expectDeleteNodesVisitor(node, '[publicKeyValueNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` someValueNode | publicKeyValueNode [73na6yX22Xw3w7q3z39MAwtZyQehEMnUQceszCt94GJ3]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/valueNodes/StringValueNode.test.ts ================================================ import { stringValueNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = stringValueNode('Hello world!'); test('mergeVisitor', () => { expectMergeVisitorCount(node, 1); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[stringValueNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor(node, `stringValueNode [Hello world!]`); }); ================================================ FILE: packages/visitors-core/test/nodes/valueNodes/StructFieldValueNode.test.ts ================================================ import { stringValueNode, structFieldValueNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = structFieldValueNode('name', stringValueNode('Alice')); test('mergeVisitor', () => { expectMergeVisitorCount(node, 2); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[structFieldValueNode]', null); expectDeleteNodesVisitor(node, '[stringValueNode]', null); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` structFieldValueNode [name] | stringValueNode [Alice]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/valueNodes/StructValueNode.test.ts ================================================ import { numberValueNode, stringValueNode, structFieldValueNode, structValueNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = structValueNode([ structFieldValueNode('name', stringValueNode('Alice')), structFieldValueNode('age', numberValueNode(42)), ]); test('mergeVisitor', () => { expectMergeVisitorCount(node, 5); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[structValueNode]', null); expectDeleteNodesVisitor(node, '[structFieldValueNode]', { ...node, fields: [] }); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` structValueNode | structFieldValueNode [name] | | stringValueNode [Alice] | structFieldValueNode [age] | | numberValueNode [42]`, ); }); ================================================ FILE: packages/visitors-core/test/nodes/valueNodes/TupleValueNode.test.ts ================================================ import { numberValueNode, publicKeyValueNode, stringValueNode, tupleValueNode } from '@codama/nodes'; import { test } from 'vitest'; import { expectDebugStringVisitor, expectDeleteNodesVisitor, expectIdentityVisitor, expectMergeVisitorCount, } from '../_setup'; const node = tupleValueNode([ stringValueNode('Hello'), numberValueNode(42), publicKeyValueNode('9sL9D2kshFgZSHz98pUQxGphwVUbCNBGqhYGaWWNJags'), ]); test('mergeVisitor', () => { expectMergeVisitorCount(node, 4); }); test('identityVisitor', () => { expectIdentityVisitor(node); }); test('deleteNodesVisitor', () => { expectDeleteNodesVisitor(node, '[tupleValueNode]', null); expectDeleteNodesVisitor(node, ['[stringValueNode]', '[numberValueNode]', '[publicKeyValueNode]'], { ...node, items: [], }); }); test('debugStringVisitor', () => { expectDebugStringVisitor( node, ` tupleValueNode | stringValueNode [Hello] | numberValueNode [42] | publicKeyValueNode [9sL9D2kshFgZSHz98pUQxGphwVUbCNBGqhYGaWWNJags]`, ); }); ================================================ FILE: packages/visitors-core/test/nonNullableIdentityVisitor.test.ts ================================================ import { assertIsNode, Node, numberTypeNode, publicKeyTypeNode, tupleTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { nonNullableIdentityVisitor, visit } from '../src'; test('it visits all nodes and returns different instances of the same nodes without returning null', () => { // Given the following 3-nodes tree. const node = tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()]); // When we visit it using the non-nullable identity visitor. const result = visit(node, nonNullableIdentityVisitor()); // Then the typed result isn't null. result satisfies Node; // And we get the same tree back. expect(result).toEqual(node); // But the nodes are different instances. expect(result).not.toBe(node); assertIsNode(result, 'tupleTypeNode'); expect(result.items[0]).not.toBe(node.items[0]); expect(result.items[1]).not.toBe(node.items[1]); }); ================================================ FILE: packages/visitors-core/test/recordLinkablesVisitor.test.ts ================================================ import { CODAMA_ERROR__LINKED_NODE_NOT_FOUND, CodamaError } from '@codama/errors'; import { accountLinkNode, AccountNode, accountNode, definedTypeLinkNode, definedTypeNode, instructionAccountLinkNode, InstructionAccountNode, instructionAccountNode, instructionArgumentLinkNode, instructionArgumentNode, instructionLinkNode, instructionNode, isNode, numberTypeNode, pdaLinkNode, pdaNode, programLinkNode, programNode, rootNode, } from '@codama/nodes'; import { expect, test } from 'vitest'; import { interceptFirstVisitVisitor, interceptVisitor, LinkableDictionary, NodeStack, recordLinkablesOnFirstVisitVisitor, visit, voidVisitor, } from '../src'; test('it records program nodes', () => { // Given the following root node containing multiple program nodes. const node = rootNode(programNode({ name: 'programA', publicKey: '1111' }), [ programNode({ name: 'programB', publicKey: '2222' }), ]); // And a recordLinkablesOnFirstVisitVisitor extending any visitor. const linkables = new LinkableDictionary(); const visitor = recordLinkablesOnFirstVisitVisitor(voidVisitor(), linkables); // When we visit the tree. visit(node, visitor); // Then we expect program paths to be recorded and retrievable. expect(linkables.getPath([programLinkNode('programA')])).toEqual([node, node.program]); expect(linkables.getPath([programLinkNode('programB')])).toEqual([node, node.additionalPrograms[0]]); }); test('it records account nodes', () => { // Given the following program node containing multiple accounts nodes. const node = programNode({ accounts: [accountNode({ name: 'accountA' }), accountNode({ name: 'accountB' })], name: 'myProgram', publicKey: '1111', }); // And a recordLinkablesOnFirstVisitVisitor extending any visitor. const linkables = new LinkableDictionary(); const visitor = recordLinkablesOnFirstVisitVisitor(voidVisitor(), linkables); // When we visit the tree. visit(node, visitor); // Then we expect account paths to be recorded and retrievable. expect(linkables.getPath([accountLinkNode('accountA', 'myProgram')])).toEqual([node, node.accounts[0]]); expect(linkables.getPath([accountLinkNode('accountB', 'myProgram')])).toEqual([node, node.accounts[1]]); }); test('it records defined type nodes', () => { // Given the following program node containing multiple defined type nodes. const node = programNode({ definedTypes: [ definedTypeNode({ name: 'typeA', type: numberTypeNode('u32') }), definedTypeNode({ name: 'typeB', type: numberTypeNode('u32') }), ], name: 'myProgram', publicKey: '1111', }); // And a recordLinkablesOnFirstVisitVisitor extending any visitor. const linkables = new LinkableDictionary(); const visitor = recordLinkablesOnFirstVisitVisitor(voidVisitor(), linkables); // When we visit the tree. visit(node, visitor); // Then we expect defined type paths to be recorded and retrievable. expect(linkables.getPath([definedTypeLinkNode('typeA', 'myProgram')])).toEqual([node, node.definedTypes[0]]); expect(linkables.getPath([definedTypeLinkNode('typeB', 'myProgram')])).toEqual([node, node.definedTypes[1]]); }); test('it records pda nodes', () => { // Given the following program node containing multiple pda nodes. const node = programNode({ name: 'myProgram', pdas: [pdaNode({ name: 'pdaA', seeds: [] }), pdaNode({ name: 'pdaB', seeds: [] })], publicKey: '1111', }); // And a recordLinkablesOnFirstVisitVisitor extending any visitor. const linkables = new LinkableDictionary(); const visitor = recordLinkablesOnFirstVisitVisitor(voidVisitor(), linkables); // When we visit the tree. visit(node, visitor); // Then we expect pda paths to be recorded and retrievable. expect(linkables.getPath([pdaLinkNode('pdaA', 'myProgram')])).toEqual([node, node.pdas[0]]); expect(linkables.getPath([pdaLinkNode('pdaB', 'myProgram')])).toEqual([node, node.pdas[1]]); }); test('it records instruction nodes', () => { // Given the following program node containing multiple instruction nodes. const node = programNode({ instructions: [instructionNode({ name: 'instructionA' }), instructionNode({ name: 'instructionB' })], name: 'myProgram', publicKey: '1111', }); // And a recordLinkablesOnFirstVisitVisitor extending any visitor. const linkables = new LinkableDictionary(); const visitor = recordLinkablesOnFirstVisitVisitor(voidVisitor(), linkables); // When we visit the tree. visit(node, visitor); // Then we expect instruction paths to be recorded and retrievable. expect(linkables.getPath([instructionLinkNode('instructionA', 'myProgram')])).toEqual([node, node.instructions[0]]); expect(linkables.getPath([instructionLinkNode('instructionB', 'myProgram')])).toEqual([node, node.instructions[1]]); }); test('it records instruction account nodes', () => { // Given the following instruction node containing multiple accounts. const instructionAccounts = [ instructionAccountNode({ isSigner: true, isWritable: false, name: 'accountA' }), instructionAccountNode({ isSigner: false, isWritable: true, name: 'accountB' }), ]; const node = programNode({ instructions: [instructionNode({ accounts: instructionAccounts, name: 'myInstruction' })], name: 'myProgram', publicKey: '1111', }); // And a recordLinkablesOnFirstVisitVisitor extending any visitor. const linkables = new LinkableDictionary(); const visitor = recordLinkablesOnFirstVisitVisitor(voidVisitor(), linkables); // When we visit the tree. visit(node, visitor); // Then we expect instruction account paths to be recorded and retrievable. const instruction = instructionLinkNode('myInstruction', 'myProgram'); expect(linkables.getPath([instructionAccountLinkNode('accountA', instruction)])).toEqual([ node, node.instructions[0], instructionAccounts[0], ]); expect(linkables.getPath([instructionAccountLinkNode('accountB', instruction)])).toEqual([ node, node.instructions[0], instructionAccounts[1], ]); }); test('it records instruction argument nodes', () => { // Given the following instruction node containing multiple arguments. const instructionArguments = [ instructionArgumentNode({ name: 'argumentA', type: numberTypeNode('u32') }), instructionArgumentNode({ name: 'argumentB', type: numberTypeNode('u32') }), ]; const node = programNode({ instructions: [instructionNode({ arguments: instructionArguments, name: 'myInstruction' })], name: 'myProgram', publicKey: '1111', }); // And a recordLinkablesOnFirstVisitVisitor extending any visitor. const linkables = new LinkableDictionary(); const visitor = recordLinkablesOnFirstVisitVisitor(voidVisitor(), linkables); // When we visit the tree. visit(node, visitor); // Then we expect instruction argument paths to be recorded and retrievable. const instruction = instructionLinkNode('myInstruction', 'myProgram'); expect(linkables.getPath([instructionArgumentLinkNode('argumentA', instruction)])).toEqual([ node, node.instructions[0], instructionArguments[0], ]); expect(linkables.getPath([instructionArgumentLinkNode('argumentB', instruction)])).toEqual([ node, node.instructions[0], instructionArguments[1], ]); }); test('it records all linkable before the first visit of the base visitor', () => { // Given the following root node with two programs. const node = rootNode(programNode({ name: 'programA', publicKey: '1111' }), [ programNode({ name: 'programB', publicKey: '2222' }), ]); // And a recordLinkablesOnFirstVisitVisitor extending a base visitor that // stores the linkable programs available at every visit. const linkables = new LinkableDictionary(); const events: string[] = []; const baseVisitor = interceptFirstVisitVisitor(voidVisitor(), (node, next) => { events.push(`programA:${linkables.has([programLinkNode('programA')])}`); events.push(`programB:${linkables.has([programLinkNode('programB')])}`); next(node); }); const visitor = recordLinkablesOnFirstVisitVisitor(baseVisitor, linkables); // When we visit the tree. visit(node, visitor); // Then we expect all linkable nodes to be recorded. expect(events).toEqual(['programA:true', 'programB:true']); }); test('it keeps track of the current program when extending a visitor', () => { // Given the following root node containing two program containing an account with the same name. const programA = programNode({ accounts: [accountNode({ name: 'someAccount' })], name: 'programA', publicKey: '1111', }); const programB = programNode({ accounts: [accountNode({ name: 'someAccount' })], name: 'programB', publicKey: '2222', }); const node = rootNode(programA, [programB]); // And a recordLinkablesOnFirstVisitVisitor extending a base visitor that checks // the result of getting the linkable node with the same name for each program. const linkables = new LinkableDictionary(); const stack = new NodeStack(); const dictionary: Record = {}; const baseVisitor = interceptVisitor(voidVisitor(), (node, next) => { stack.push(node); if (isNode(node, 'programNode')) { dictionary[node.name] = linkables.getOrThrow([...stack.getPath(), accountLinkNode('someAccount')]); } next(node); stack.pop(); }); const visitor = recordLinkablesOnFirstVisitVisitor(baseVisitor, linkables); // When we visit the tree. visit(node, visitor); // Then we expect each program to have its own account. expect(dictionary.programA).toBe(programA.accounts[0]); expect(dictionary.programB).toBe(programB.accounts[0]); }); test('it keeps track of the current instruction when extending a visitor', () => { // Given the following program node containing two instructions each containing an account with the same name. const node = programNode({ instructions: [ instructionNode({ accounts: [instructionAccountNode({ isSigner: true, isWritable: false, name: 'someAccount' })], name: 'instructionA', }), instructionNode({ accounts: [instructionAccountNode({ isSigner: true, isWritable: false, name: 'someAccount' })], name: 'instructionB', }), ], name: 'myProgram', publicKey: '1111', }); // And a recordLinkablesOnFirstVisitVisitor extending a base visitor that checks // the result of getting the linkable node with the same name for each instruction. const linkables = new LinkableDictionary(); const stack = new NodeStack(); const dictionary: Record = {}; const baseVisitor = interceptVisitor(voidVisitor(), (node, next) => { stack.push(node); if (isNode(node, 'instructionNode')) { dictionary[node.name] = linkables.getOrThrow([ ...stack.getPath(), instructionAccountLinkNode('someAccount'), ]); } next(node); stack.pop(); }); const visitor = recordLinkablesOnFirstVisitVisitor(baseVisitor, linkables); // When we visit the tree. visit(node, visitor); // Then we expect each instruction to have its own account. expect(dictionary.instructionA).toBe(node.instructions[0].accounts[0]); expect(dictionary.instructionB).toBe(node.instructions[1].accounts[0]); }); test('it does not record linkable types that are not under a program node', () => { // Given the following account node that is not under a program node. const node = accountNode({ name: 'someAccount' }); // And a recordLinkablesOnFirstVisitVisitor extending a void visitor. const linkables = new LinkableDictionary(); const visitor = recordLinkablesOnFirstVisitVisitor(voidVisitor(), linkables); // When we visit the node. visit(node, visitor); // Then we expect the account node to not be recorded. expect(linkables.has([accountLinkNode('someAccount')])).toBe(false); }); test('it can throw an exception when trying to retrieve a missing linked node', () => { // Given the following program node with one account. const node = programNode({ accounts: [accountNode({ name: 'myAccount' })], name: 'myProgram', publicKey: '1111', }); // And a recorded LinkableDictionary. const linkables = new LinkableDictionary(); const visitor = recordLinkablesOnFirstVisitVisitor(voidVisitor(), linkables); visit(node, visitor); // When we try to retrieve a missing account node. const linkNode = accountLinkNode('missingAccount', 'myProgram'); const getMissingAccount = () => linkables.getOrThrow([node, linkNode]); // Then we expect an exception to be thrown. expect(getMissingAccount).toThrow( new CodamaError(CODAMA_ERROR__LINKED_NODE_NOT_FOUND, { kind: 'accountLinkNode', linkNode, name: 'missingAccount', path: [node, linkNode], }), ); }); ================================================ FILE: packages/visitors-core/test/recordNodeStackVisitor.test.ts ================================================ import { definedTypeNode, numberTypeNode, publicKeyTypeNode, TupleTypeNode, tupleTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { NodeStack, pipe, recordNodeStackVisitor, tapVisitor, visit, voidVisitor } from '../src'; test('it records the current node stack of a visit', () => { // Given the following tree. const node = definedTypeNode({ name: 'myType', type: tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()]), }); // And a visitor that records the current node stack and stores the number stacks in an array. const stack = new NodeStack(); const numberStacks: NodeStack[] = []; const visitor = pipe( voidVisitor(), v => recordNodeStackVisitor(v, stack), v => tapVisitor(v, 'numberTypeNode', () => numberStacks.push(stack.clone())), ); // When we visit the tree. visit(node, visitor); // Then we expect the number stacks to have been recorded. expect(numberStacks.length).toBe(1); expect(numberStacks[0].getPath()).toEqual([node, node.type]); // And the current node stack to be empty. expect(stack.isEmpty()).toBe(true); }); test('it includes the current node when applied last', () => { // Given the following tree. const node = definedTypeNode({ name: 'myType', type: tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()]), }); // And a visitor that records the current node stack as the last visitor modifier. const stack = new NodeStack(); const numberStacks: NodeStack[] = []; const visitor = pipe( voidVisitor(), v => tapVisitor(v, 'numberTypeNode', () => numberStacks.push(stack.clone())), v => recordNodeStackVisitor(v, stack), ); // When we visit the tree. visit(node, visitor); // Then we expect the number stacks to have been recorded // such that the number node themselves are included in the stack. expect(numberStacks.length).toBe(1); expect(numberStacks[0].getPath()).toEqual([node, node.type, (node.type as TupleTypeNode).items[0]]); }); ================================================ FILE: packages/visitors-core/test/removeDocsVisitor.test.ts ================================================ import { numberTypeNode, publicKeyTypeNode, structFieldTypeNode, structTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { removeDocsVisitor, visit } from '../src'; test('it empties the docs array of any node that contains docs', () => { // Given the following struct node with docs. const node = structTypeNode([ structFieldTypeNode({ docs: ['The owner of the account.'], name: 'owner', type: publicKeyTypeNode(), }), structFieldTypeNode({ docs: ['The wallet allowed to modify the account.'], name: 'authority', type: publicKeyTypeNode(), }), structFieldTypeNode({ docs: ['The amount of tokens in basis points.'], name: 'amount', type: numberTypeNode('u64'), }), ]); // When we remove the docs from the node. const result = visit(node, removeDocsVisitor()); // Then we expect the following node. expect(result).toEqual( structTypeNode([ structFieldTypeNode({ docs: [], name: 'owner', type: publicKeyTypeNode(), }), structFieldTypeNode({ docs: [], name: 'authority', type: publicKeyTypeNode(), }), structFieldTypeNode({ docs: [], name: 'amount', type: numberTypeNode('u64'), }), ]), ); }); test('it freezes the returned node', () => { // Given the following struct node with docs. const node = structTypeNode([ structFieldTypeNode({ docs: ['The owner of the account.'], name: 'owner', type: publicKeyTypeNode(), }), ]); // When we remove the docs from the node. const result = visit(node, removeDocsVisitor()); // Then we expect the returned node to be frozen. expect(Object.isFrozen(result)).toBe(true); }); test('it can create partial visitors', () => { // Given the following struct node with docs. const node = structTypeNode([ structFieldTypeNode({ docs: ['The owner of the account.'], name: 'owner', type: publicKeyTypeNode(), }), ]); // And a remove docs visitor that only supports struct type nodes. const visitor = removeDocsVisitor({ keys: ['structTypeNode'] }); // When we use it on our struct node. const result = visit(node, visitor); // Then we expect the same node back. expect(result).toEqual(node); // And we expect an error when visiting an unsupported node. // @ts-expect-error StructFieldTypeNode is not supported. expect(() => visit(node.fields[0], visitor)).toThrow(); }); ================================================ FILE: packages/visitors-core/test/singleNodeVisitor.test.ts ================================================ import { numberTypeNode, ProgramNode, publicKeyTypeNode, rootNode, tupleTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { rootNodeVisitor, singleNodeVisitor, visit } from '../src'; test('it visits a single node and return a custom value', () => { // Given the following tree. const node = tupleTypeNode([numberTypeNode('u32'), tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()])]); // And a visitor that counts the number of direct items in a tuple node. const visitor = singleNodeVisitor('tupleTypeNode', node => node.items.length); // When we visit the tree using that visitor. const result = visit(node, visitor); // Then we expect 2 direct items in the tuple node. expect(result).toEqual(2); // And no other nodes can be visited. // @ts-expect-error NumberTypeNode is not supported. expect(() => visit(numberTypeNode('u64'), visitor)).toThrow(); // @ts-expect-error PublicKeyTypeNode is not supported. expect(() => visit(publicKeyTypeNode(), visitor)).toThrow(); }); test('it can create rootNode only visitors that return new rootNode instances', () => { // Given a root node. const node = rootNode({} as ProgramNode); // And a root node visitor that adds an additional program node. const visitor = rootNodeVisitor(node => rootNode(node.program, [...node.additionalPrograms, {} as ProgramNode])); // When we visit the empty root node using that visitor. const result = visit(node, visitor); // Then we expect the returned root node to have one additional program node. expect(result.additionalPrograms.length).toBe(1); }); ================================================ FILE: packages/visitors-core/test/staticVisitor.test.ts ================================================ import { numberTypeNode, publicKeyTypeNode, tupleTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { staticVisitor, visit } from '../src'; test('it returns the same value for any visited node', () => { // Given the following 3-nodes tree. const node = tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()]); // And a static visitor that returns the node kind for any visited node. const visitor = staticVisitor(node => node.kind); // Then we expect the following results when visiting different nodes. expect(visit(node, visitor)).toBe('tupleTypeNode'); expect(visit(node.items[0], visitor)).toBe('numberTypeNode'); expect(visit(node.items[1], visitor)).toBe('publicKeyTypeNode'); }); test('it can create partial visitor', () => { // Given the following 3-nodes tree. const node = tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()]); // And a static visitor that supports only 2 of these nodes. const visitor = staticVisitor(node => node.kind, { keys: ['tupleTypeNode', 'numberTypeNode'] }); // Then we expect the following results when visiting supported nodes. expect(visit(node, visitor)).toBe('tupleTypeNode'); expect(visit(node.items[0], visitor)).toBe('numberTypeNode'); // But expect an error when visiting an unsupported node. // @ts-expect-error PublicKeyTypeNode is not supported. expect(() => visit(node.items[1], visitor)).toThrow(); }); ================================================ FILE: packages/visitors-core/test/tapVisitor.test.ts ================================================ import { NumberTypeNode, numberTypeNode, publicKeyTypeNode, tupleTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { mergeVisitor, tapVisitor, visit } from '../src'; test('it returns a new instance of the same visitor whilst tapping into one of its visits', () => { // Given the following tree. const node = tupleTypeNode([numberTypeNode('u32'), tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()])]); // And a sum visitor that counts the nodes. const visitor = mergeVisitor( () => 1, (_, values) => values.reduce((a, b) => a + b, 1), ); // And a tap visitor that taps into the numberTypeNode visit and counts them. let numberOfNumberNodes = 0; const tappedVisitor = tapVisitor(visitor, 'numberTypeNode', node => { node satisfies NumberTypeNode; numberOfNumberNodes++; }); // When we visit the tree using the tapped visitor. const result = visit(node, tappedVisitor); // Then we get the expected result. expect(result).toBe(5); // And the tapped counter is also correct. expect(numberOfNumberNodes).toBe(2); // And the tapped visitor is a new instance. expect(visitor).not.toBe(tappedVisitor); }); ================================================ FILE: packages/visitors-core/test/topDownTransformerVisitor.test.ts ================================================ import { assertIsNode, definedTypeNode, isNode, numberTypeNode, programNode, publicKeyTypeNode, tupleTypeNode, } from '@codama/nodes'; import { expect, test } from 'vitest'; import { findProgramNodeFromPath, NodeStack, TopDownNodeTransformerWithSelector, topDownTransformerVisitor, visit, } from '../src'; test('it can transform nodes to the same kind of node', () => { // Given the following tree. const node = tupleTypeNode([numberTypeNode('u32'), tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()])]); // And a transformer visitor that transforms all number nodes into u64 number nodes. const visitor = topDownTransformerVisitor([ node => (isNode(node, 'numberTypeNode') ? (numberTypeNode('u64') as typeof node) : node), ]); // When we visit the tree using that visitor. const result = visit(node, visitor); // Then we expect the number nodes to have been transformed into u64 number nodes. expect(result).toEqual( tupleTypeNode([numberTypeNode('u64'), tupleTypeNode([numberTypeNode('u64'), publicKeyTypeNode()])]), ); }); test('it can transform nodes using node selectors', () => { // Given the following tree. const node = tupleTypeNode([numberTypeNode('u32'), tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()])]); // And a transformer visitor that uses a node selector to select all number nodes. const visitor = topDownTransformerVisitor([ { select: '[numberTypeNode]', transform: _node => numberTypeNode('u64') as typeof _node, }, ]); // When we visit the tree using that visitor. const result = visit(node, visitor); // Then we expect the number nodes to have been transformed into u64 number nodes. expect(result).toEqual( tupleTypeNode([numberTypeNode('u64'), tupleTypeNode([numberTypeNode('u64'), publicKeyTypeNode()])]), ); }); test('it can create partial transformer visitors', () => { // Given the following tree. const node = tupleTypeNode([numberTypeNode('u32'), tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()])]); // And a tuple-only transformer visitor that prefixes all tuples with another number node. const visitor = topDownTransformerVisitor( [ { select: '[tupleTypeNode]', transform: node => { assertIsNode(node, 'tupleTypeNode'); return tupleTypeNode([numberTypeNode('u64'), ...node.items]) as unknown as typeof node; }, }, ], { keys: ['tupleTypeNode'] }, ); // When we visit the tree using that visitor. const result = visit(node, visitor); // Then we expect the following tree. expect(result).toEqual( tupleTypeNode([ numberTypeNode('u64'), numberTypeNode('u32'), tupleTypeNode([numberTypeNode('u64'), numberTypeNode('u32'), publicKeyTypeNode()]), ]), ); // And the other nodes cannot be visited. // @ts-expect-error NumberTypeNode is not a tuple node. expect(() => visit(numberTypeNode('u64'), visitor)).toThrow(); // @ts-expect-error PublicKeyTypeNode is not a tuple node. expect(() => visit(publicKeyTypeNode(), visitor)).toThrow(); }); test('it can be used to delete nodes', () => { // Given the following tree. const node = tupleTypeNode([numberTypeNode('u32'), tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()])]); // And a transformer visitor that deletes all number nodes. const visitor = topDownTransformerVisitor([{ select: '[numberTypeNode]', transform: () => null }]); // When we visit the tree using that visitor. const result = visit(node, visitor); // Then we expect the number nodes to have been deleted. expect(result).toEqual(tupleTypeNode([tupleTypeNode([publicKeyTypeNode()])])); }); test('it can transform nodes using multiple node selectors', () => { // Given the following tree. const node = tupleTypeNode([numberTypeNode('u32'), tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()])]); // And a transformer visitor that uses two node selectors such that // - the first one selects all number nodes, and // - the second one selects all nodes with more than one ancestor. const visitor = topDownTransformerVisitor([ { select: ['[numberTypeNode]', path => path.length > 2], transform: _node => numberTypeNode('u64') as typeof _node, }, ]); // When we visit the tree using that visitor. const result = visit(node, visitor); // Then we expect both node selectors to have been applied. expect(result).toEqual( tupleTypeNode([numberTypeNode('u32'), tupleTypeNode([numberTypeNode('u64'), publicKeyTypeNode()])]), ); }); test('it can start from an existing stack', () => { // Given the following tuple node inside a program node. const tuple = tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()]); const program = programNode({ definedTypes: [definedTypeNode({ name: 'myTuple', type: tuple })], name: 'myProgram', publicKey: '1111', }); // And a transformer that removes all number nodes // from programs whose public key is '1111'. const transformer: TopDownNodeTransformerWithSelector = { select: ['[numberTypeNode]', path => findProgramNodeFromPath(path)?.publicKey === '1111'], transform: () => null, }; // When we visit the tuple with an existing stack that contains the program node. const stack = new NodeStack([program, program.definedTypes[0]]); const resultWithStack = visit(tuple, topDownTransformerVisitor([transformer], { stack })); // Then we expect the number node to have been removed. expect(resultWithStack).toStrictEqual(tupleTypeNode([publicKeyTypeNode()])); // But when we visit the tuple without the stack. const resultWithoutStack = visit(tuple, topDownTransformerVisitor([transformer])); // Then we expect the number node to have been kept. expect(resultWithoutStack).toStrictEqual(tuple); }); ================================================ FILE: packages/visitors-core/test/visitor.test.ts ================================================ import { NumberTypeNode, numberTypeNode, PublicKeyTypeNode, publicKeyTypeNode, TupleTypeNode, tupleTypeNode, } from '@codama/nodes'; import { expect, test } from 'vitest'; import { visit, Visitor, visitOrElse } from '../src'; test('it can create visitors as plain objects', () => { // Given the following tree. const node = tupleTypeNode([numberTypeNode('u32'), tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()])]); // And a plain object visitor that counts the nodes with different weights. const visitor: Visitor = { visitNumberType() { return 1; }, visitPublicKeyType() { return 2; }, visitTupleType(node) { const castedChildren = node.items as (NumberTypeNode | PublicKeyTypeNode | TupleTypeNode)[]; return castedChildren.map(child => visit(child, this)).reduce((a, b) => a + b, 10); }, }; // When we visit the tree using that visitor. const result = visit(node, visitor); // Then we expect the following count. expect(result).toBe(24); }); test('it can use visitOrElse to fallback if a nested node is not supported by the visitor', () => { // Given the following tree. const node = tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()]); // And a plain object visitor that counts the tuples and numbers nodes only // Such that it falls back to 42 for any other node. const visitor: Visitor = { visitNumberType() { return 1; }, visitTupleType(node) { return node.items.map(child => visitOrElse(child, this, () => 42)).reduce((a, b) => a + b, 1); }, }; // When we visit the tree using that visitor. const result = visit(node, visitor); // Then we expect the following count. expect(result).toBe(44); }); ================================================ FILE: packages/visitors-core/test/voidVisitor.test.ts ================================================ import { numberTypeNode, publicKeyTypeNode, tupleTypeNode } from '@codama/nodes'; import { expect, test } from 'vitest'; import { extendVisitor, visit, voidVisitor } from '../src'; test('it visits all nodes and returns void', () => { // Given the following tree. const node = tupleTypeNode([numberTypeNode('u32'), tupleTypeNode([numberTypeNode('u32'), publicKeyTypeNode()])]); // And a void visitor extended such that it counts the tuple nodes. let counter = 0; const visitor = extendVisitor(voidVisitor(), { visitTupleType: (node, { next }) => { counter++; return next(node); }, }); // When we visit the tree using that visitor. const result = visit(node, visitor); // Then we expect the counter to match the amount of tuple nodes. expect(counter).toBe(2); // And a void result. expect(result).toBeUndefined(); }); ================================================ FILE: packages/visitors-core/tsconfig.declarations.json ================================================ { "compilerOptions": { "declaration": true, "declarationMap": true, "emitDeclarationOnly": true, "outDir": "./dist/types" }, "extends": "./tsconfig.json", "include": ["src/index.ts", "src/types"] } ================================================ FILE: packages/visitors-core/tsconfig.json ================================================ { "$schema": "https://json.schemastore.org/tsconfig", "compilerOptions": { "lib": [] }, "display": "@codama/visitors-core", "extends": "../../tsconfig.json", "include": ["src", "test"] } ================================================ FILE: packages/visitors-core/tsup.config.ts ================================================ import { defineConfig } from 'tsup'; import { getPackageBuildConfigs } from '../../tsup.config.base'; export default defineConfig(getPackageBuildConfigs()); ================================================ FILE: packages/visitors-core/vitest.config.mts ================================================ import { defineConfig } from 'vitest/config'; import { getVitestConfig } from '../../vitest.config.base.mjs'; export default defineConfig({ test: { projects: [getVitestConfig('browser'), getVitestConfig('node'), getVitestConfig('react-native')], }, }); ================================================ FILE: pnpm-workspace.yaml ================================================ packages: - "packages/*" ================================================ FILE: tsconfig.json ================================================ { "$schema": "https://json.schemastore.org/tsconfig", "compilerOptions": { "composite": false, "declaration": true, "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "inlineSources": false, "isolatedModules": true, "moduleResolution": "node", "noFallthroughCasesInSwitch": true, "noUnusedLocals": true, "noUnusedParameters": true, "preserveWatchOutput": true, "skipLibCheck": true, "strict": true, "target": "ESNext" }, "exclude": ["node_modules"] } ================================================ FILE: tsup.config.base.ts ================================================ import { env } from 'node:process'; import browsersListToEsBuild from 'browserslist-to-esbuild'; import { Format, Options as TsupConfig } from 'tsup'; type Platform = 'browser' | 'node' | 'react-native'; type BuildOptions = { format: Format; platform: Platform; }; const BROWSERSLIST_TARGETS = browsersListToEsBuild(); export function getBuildConfig(options: BuildOptions): TsupConfig { const { format, platform } = options; return { define: { __BROWSER__: `${platform === 'browser'}`, __ESM__: `${format === 'esm'}`, __NODEJS__: `${platform === 'node'}`, __REACTNATIVE__: `${platform === 'react-native'}`, __TEST__: 'false', __VERSION__: `"${env.npm_package_version}"`, }, entry: [`./src/index.ts`], esbuildOptions(options, context) { if (context.format === 'iife') { options.target = BROWSERSLIST_TARGETS; options.minify = true; } else { options.define = { ...options.define, 'process.env.NODE_ENV': 'process.env.NODE_ENV', }; } }, external: ['node:fs', 'node:path', 'node:url'], format, globalName: 'globalThis.codama', name: platform, // Inline private, non-published packages. // WARNING: This inlines packages recursively. Make sure these don't have deep dep trees. noExternal: [ // @noble/hashes/sha256 is an ESM-only module, so we have to inline it in CJS builds. ...(format === 'cjs' ? ['@noble/hashes/sha256', '@noble/hashes/crypto'] : []), ], outExtension({ format }) { const extension = format === 'iife' ? `.production.min.js` : `.${platform}.${format === 'cjs' ? 'cjs' : 'mjs'}`; return { js: extension }; }, platform: platform === 'node' ? 'node' : 'browser', publicDir: true, pure: ['process'], sourcemap: format !== 'iife', treeshake: true, }; } export function getPackageBuildConfigs(): TsupConfig[] { return [ getBuildConfig({ format: 'cjs', platform: 'node' }), getBuildConfig({ format: 'esm', platform: 'node' }), getBuildConfig({ format: 'cjs', platform: 'browser' }), getBuildConfig({ format: 'esm', platform: 'browser' }), getBuildConfig({ format: 'esm', platform: 'react-native' }), ]; } export function getCliBuildConfig(): TsupConfig { return { ...getBuildConfig({ format: 'cjs', platform: 'node' }), entry: { cli: './src/cli/index.ts' }, outExtension() { return { js: `.cjs` }; }, }; } ================================================ FILE: turbo.json ================================================ { "$schema": "https://turbo.build/schema.json", "globalEnv": ["NODE_ENV"], "remoteCache": { "signature": true }, "tasks": { "build": { "dependsOn": ["^build"] }, "test": { "dependsOn": ["build"] }, "test:browser": { "dependsOn": ["^build"] }, "test:node": { "dependsOn": ["^build"] }, "test:react-native": { "dependsOn": ["^build"] }, "test:treeshakability": { "dependsOn": ["build"] }, "test:types": {}, "lint": { "inputs": ["$TURBO_DEFAULT$", "../../eslint.config.*"], "outputs": [] }, "lint:fix": { "inputs": ["$TURBO_DEFAULT$", "../../eslint.config.*"], "outputs": ["*"] } } } ================================================ FILE: vitest.config.base.mts ================================================ import { env } from 'node:process'; import { configDefaults, defineConfig } from 'vitest/config'; export type Platform = 'browser' | 'node' | 'react-native'; export function getVitestConfig(platform: Platform) { return defineConfig({ define: { __BROWSER__: `${platform === 'browser'}`, __ESM__: 'true', __NODEJS__: `${platform === 'node'}`, __REACTNATIVE__: `${platform === 'react-native'}`, __TEST__: 'true', __VERSION__: `"${env.npm_package_version}"`, }, test: { environment: platform === 'browser' ? 'happy-dom' : 'node', exclude: [...configDefaults.exclude, '**/e2e/**'], name: platform, }, }); } ================================================ FILE: vitest.config.mts ================================================ import { defineConfig } from 'vitest/config'; import { getVitestConfig } from './vitest.config.base.mjs'; /** * This config file is not directly used by packages scripts or CI. * It's only purpose is to provide IDEs with a default configuration * so features from Vitest extensions can work out of the box. * * Ideally, this will be used in the future once Vitest supports hierarchical subprojects. * @see https://github.com/vitest-dev/vitest/issues/8226 */ export default defineConfig(getVitestConfig('node'));