Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[experimental] Use account name directly for data types and codecs #212

Merged
merged 3 commits into from
Apr 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/witty-dryers-beg.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@metaplex-foundation/kinobi": minor
---

Use account name directly for data types and codecs
14 changes: 7 additions & 7 deletions src/renderers/js-experimental/fragments/accountFetchHelpers.njk
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
export function {{ decodeFunction }}<TAddress extends string = string>(encodedAccount: EncodedAccount<TAddress>): {{ accountType }}<TAddress>;
export function {{ decodeFunction }}<TAddress extends string = string>(encodedAccount: MaybeEncodedAccount<TAddress>): {{ accountMaybeType }}<TAddress>;
export function {{ decodeFunction }}<TAddress extends string = string>(encodedAccount: EncodedAccount<TAddress> | MaybeEncodedAccount<TAddress>): {{ accountType }}<TAddress> | {{ accountMaybeType }}<TAddress> {
export function {{ decodeFunction }}<TAddress extends string = string>(encodedAccount: EncodedAccount<TAddress>): Account<{{ accountType }}, TAddress>;
export function {{ decodeFunction }}<TAddress extends string = string>(encodedAccount: MaybeEncodedAccount<TAddress>): MaybeAccount<{{ accountType }}, TAddress>;
export function {{ decodeFunction }}<TAddress extends string = string>(encodedAccount: EncodedAccount<TAddress> | MaybeEncodedAccount<TAddress>): Account<{{ accountType }}, TAddress> | MaybeAccount<{{ accountType }}, TAddress> {
return decodeAccount(encodedAccount as MaybeEncodedAccount<TAddress>, {{ decoderFunction }});
}

export async function {{ fetchFunction }}<TAddress extends string = string>(
rpc: Parameters<typeof fetchEncodedAccount>[0],
address: Address<TAddress>,
config?: FetchAccountConfig,
): Promise<{{ accountType }}<TAddress>> {
): Promise<Account<{{ accountType }}, TAddress>> {
const maybeAccount = await {{ fetchMaybeFunction }}(rpc, address, config);
assertAccountExists(maybeAccount);
return maybeAccount;
Expand All @@ -18,7 +18,7 @@ export async function {{ fetchMaybeFunction }}<TAddress extends string = string>
rpc: Parameters<typeof fetchEncodedAccount>[0],
address: Address<TAddress>,
config?: FetchAccountConfig,
): Promise<{{ accountMaybeType }}<TAddress>> {
): Promise<MaybeAccount<{{ accountType }}, TAddress>> {
const maybeAccount = await fetchEncodedAccount(rpc, address, config);
return {{ decodeFunction }}(maybeAccount);
}
Expand All @@ -27,7 +27,7 @@ export async function {{ fetchAllFunction }}(
rpc: Parameters<typeof fetchEncodedAccounts>[0],
addresses: Array<Address>,
config?: FetchAccountsConfig,
): Promise<{{ accountType }}[]> {
): Promise<Account<{{ accountType }}>[]> {
const maybeAccounts = await {{ fetchAllMaybeFunction }}(rpc, addresses, config);
assertAccountsExist(maybeAccounts);
return maybeAccounts;
Expand All @@ -37,7 +37,7 @@ export async function {{ fetchAllMaybeFunction }}(
rpc: Parameters<typeof fetchEncodedAccounts>[0],
addresses: Array<Address>,
config?: FetchAccountsConfig,
): Promise<{{ accountMaybeType }}[]> {
): Promise<MaybeAccount<{{ accountType }}>[]> {
const maybeAccounts = await fetchEncodedAccounts(rpc, addresses, config);
return maybeAccounts.map((maybeAccount) => {{ decodeFunction }}(maybeAccount));
}
16 changes: 10 additions & 6 deletions src/renderers/js-experimental/fragments/accountFetchHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,17 @@ export function getAccountFetchHelpersFragment(
}
): Fragment {
const { accountNode, typeManifest, nameApi, customAccountData } = scope;
const accountDataName = nameApi.accountDataType(accountNode.name);
const decoderFunctionFragment = customAccountData.has(accountNode.name)
const hasCustomData = customAccountData.has(accountNode.name);
const accountTypeFragment = hasCustomData
? typeManifest.strictType.clone()
: fragment(nameApi.dataType(accountNode.name));
const decoderFunctionFragment = hasCustomData
? typeManifest.decoder.clone()
: fragment(`${nameApi.decoderFunction(accountDataName)}()`);
: fragment(`${nameApi.decoderFunction(accountNode.name)}()`);

return fragmentFromTemplate('accountFetchHelpers.njk', {
decoderFunction: decoderFunctionFragment.render,
accountType: nameApi.accountType(accountNode.name),
accountMaybeType: nameApi.accountMaybeType(accountNode.name),
accountType: accountTypeFragment.render,
decodeFunction: nameApi.accountDecodeFunction(accountNode.name),
fetchFunction: nameApi.accountFetchFunction(accountNode.name),
fetchMaybeFunction: nameApi.accountFetchMaybeFunction(accountNode.name),
Expand All @@ -27,9 +29,10 @@ export function getAccountFetchHelpersFragment(
accountNode.name
),
})
.mergeImportsWith(decoderFunctionFragment)
.mergeImportsWith(accountTypeFragment, decoderFunctionFragment)
.addImports('solanaAddresses', ['Address'])
.addImports('solanaAccounts', [
'Account',
'assertAccountExists',
'assertAccountsExist',
'decodeAccount',
Expand All @@ -38,6 +41,7 @@ export function getAccountFetchHelpersFragment(
'fetchEncodedAccounts',
'FetchAccountConfig',
'FetchAccountsConfig',
'MaybeAccount',
'MaybeEncodedAccount',
]);
}
4 changes: 2 additions & 2 deletions src/renderers/js-experimental/fragments/accountPdaHelpers.njk
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export async function {{ fetchFromSeedsFunction }}(
seeds: {{ pdaSeedsType }},
{% endif %}
config: FetchAccountConfig & { programAddress?: Address } = {},
): Promise<{{ accountType }}> {
): Promise<Account<{{ accountType }}>> {
const maybeAccount = await {{ fetchMaybeFromSeedsFunction }}(rpc, {% if hasVariableSeeds %}seeds, {% endif %}config);
assertAccountExists(maybeAccount);
return maybeAccount;
Expand All @@ -18,7 +18,7 @@ export async function {{ fetchMaybeFromSeedsFunction }}(
seeds: {{ pdaSeedsType }},
{% endif %}
config: FetchAccountConfig & { programAddress?: Address } = {},
): Promise<{{ accountMaybeType }}> {
): Promise<MaybeAccount<{{ accountType }}>> {
const { programAddress, ...fetchConfig } = config;
const [address] = await {{ findPdaFunction }}({% if hasVariableSeeds %}seeds, {% endif %}{ programAddress });
return await {{ fetchMaybeFunction }}(rpc, address, fetchConfig);
Expand Down
26 changes: 22 additions & 4 deletions src/renderers/js-experimental/fragments/accountPdaHelpers.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,43 @@
import { AccountNode, ProgramNode, isNodeFilter } from '../../../nodes';
import type { TypeManifest } from '../TypeManifest';
import type { GlobalFragmentScope } from '../getRenderMapVisitor';
import { Fragment, fragment, fragmentFromTemplate } from './common';

export function getAccountPdaHelpersFragment(
scope: Pick<GlobalFragmentScope, 'nameApi' | 'linkables'> & {
scope: Pick<
GlobalFragmentScope,
'nameApi' | 'linkables' | 'customAccountData'
> & {
accountNode: AccountNode;
programNode: ProgramNode;
typeManifest: TypeManifest;
}
): Fragment {
const { accountNode, programNode, nameApi, linkables } = scope;
const {
accountNode,
programNode,
nameApi,
linkables,
customAccountData,
typeManifest,
} = scope;
const pdaNode = accountNode.pda ? linkables.get(accountNode.pda) : undefined;
if (!pdaNode) {
return fragment('');
}

const accountTypeFragment = customAccountData.has(accountNode.name)
? typeManifest.strictType.clone()
: fragment(nameApi.dataType(accountNode.name));

const importFrom = 'generatedPdas';
const pdaSeedsType = nameApi.pdaSeedsType(pdaNode.name);
const findPdaFunction = nameApi.pdaFindFunction(pdaNode.name);
const hasVariableSeeds =
pdaNode.seeds.filter(isNodeFilter('variablePdaSeedNode')).length > 0;

return fragmentFromTemplate('accountPdaHelpers.njk', {
accountType: nameApi.accountType(accountNode.name),
accountMaybeType: nameApi.accountMaybeType(accountNode.name),
accountType: accountTypeFragment.render,
pdaSeedsType,
findPdaFunction,
fetchFunction: nameApi.accountFetchFunction(accountNode.name),
Expand All @@ -36,13 +51,16 @@ export function getAccountPdaHelpersFragment(
program: programNode,
hasVariableSeeds,
})
.mergeImportsWith(accountTypeFragment)
.addImports(
importFrom,
hasVariableSeeds ? [pdaSeedsType, findPdaFunction] : [findPdaFunction]
)
.addImports('solanaAddresses', ['Address'])
.addImports('solanaAccounts', [
'Account',
'assertAccountExists',
'FetchAccountConfig',
'MaybeAccount',
]);
}
8 changes: 0 additions & 8 deletions src/renderers/js-experimental/fragments/accountType.njk

This file was deleted.

30 changes: 9 additions & 21 deletions src/renderers/js-experimental/fragments/accountType.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { AccountNode } from '../../../nodes';
import { TypeManifest } from '../TypeManifest';
import type { GlobalFragmentScope } from '../getRenderMapVisitor';
import { Fragment, fragment, fragmentFromTemplate } from './common';
import { Fragment, fragment } from './common';
import { getTypeWithCodecFragment } from './typeWithCodec';

export function getAccountTypeFragment(
Expand All @@ -11,26 +11,14 @@ export function getAccountTypeFragment(
}
): Fragment {
const { accountNode, typeManifest, nameApi, customAccountData } = scope;
const customData = customAccountData.get(accountNode.name);
const accountDataName = nameApi.accountDataType(accountNode.name);
const typeWithCodecFragment = customData
? fragment('')
: getTypeWithCodecFragment({
name: accountDataName,
manifest: typeManifest,
nameApi,
});

const dataNameFragment = customData
? typeManifest.strictType.clone()
: fragment(nameApi.dataType(accountDataName));
if (customAccountData.has(accountNode.name)) {
return fragment('');
}

return fragmentFromTemplate('accountType.njk', {
accountType: nameApi.accountType(accountNode.name),
accountMaybeType: nameApi.accountMaybeType(accountNode.name),
dataName: dataNameFragment.render,
typeWithCodec: typeWithCodecFragment,
})
.mergeImportsWith(dataNameFragment, typeWithCodecFragment)
.addImports('solanaAccounts', ['Account', 'MaybeAccount']);
return getTypeWithCodecFragment({
name: accountNode.name,
manifest: typeManifest,
nameApi,
});
}
1 change: 0 additions & 1 deletion src/renderers/js-experimental/fragments/pdaFunction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ export function getPdaFunctionFragment(
pdaNode.seeds.filter(isNodeFilter('variablePdaSeedNode')).length > 0;

return fragmentFromTemplate('pdaFunction.njk', {
accountType: nameApi.accountType(pdaNode.name),
pdaSeedsType: nameApi.pdaSeedsType(pdaNode.name),
findPdaFunction: nameApi.pdaFindFunction(pdaNode.name),
program: programNode,
Expand Down
5 changes: 2 additions & 3 deletions src/renderers/js-experimental/getTypeManifestVisitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,9 @@ export function getTypeManifestVisitor(input: {
(visitor) =>
extendVisitor(visitor, {
visitAccount(account, { self }) {
const accountDataName = nameApi.accountDataType(account.name);
parentName = {
strict: nameApi.dataType(accountDataName),
loose: nameApi.dataArgsType(accountDataName),
strict: nameApi.dataType(account.name),
loose: nameApi.dataArgsType(account.name),
};
const link = customAccountData.get(account.name)?.linkNode;
const manifest = link ? visit(link, self) : visit(account.data, self);
Expand Down
6 changes: 0 additions & 6 deletions src/renderers/js-experimental/nameTransformers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,6 @@ export type NameTransformerKey =
| 'codecFunction'
| 'pdaSeedsType'
| 'pdaFindFunction'
| 'accountType'
| 'accountMaybeType'
| 'accountDataType'
| 'accountDecodeFunction'
| 'accountFetchFunction'
| 'accountFetchAllFunction'
Expand Down Expand Up @@ -99,9 +96,6 @@ export const DEFAULT_NAME_TRANSFORMERS: NameTransformers = {
codecFunction: (name) => `get${pascalCase(name)}Codec`,
pdaSeedsType: (name) => `${pascalCase(name)}Seeds`,
pdaFindFunction: (name) => `find${pascalCase(name)}Pda`,
accountType: (name) => `${pascalCase(name)}`,
accountMaybeType: (name) => `Maybe${pascalCase(name)}`,
accountDataType: (name) => `${pascalCase(name)}AccountData`,
accountDecodeFunction: (name) => `decode${pascalCase(name)}`,
accountFetchFunction: (name) => `fetch${pascalCase(name)}`,
accountFetchAllFunction: (name) => `fetchAll${pascalCase(name)}`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,7 @@ import {
getCandyMachineDataEncoder,
} from '../types';

export type CandyMachine<TAddress extends string = string> = Account<
CandyMachineAccountData,
TAddress
>;

export type MaybeCandyMachine<TAddress extends string = string> = MaybeAccount<
CandyMachineAccountData,
TAddress
>;

export type CandyMachineAccountData = {
export type CandyMachine = {
discriminator: Array<number>;
/** Features versioning flags. */
features: bigint;
Expand All @@ -72,7 +62,7 @@ export type CandyMachineAccountData = {
data: CandyMachineData;
};

export type CandyMachineAccountDataArgs = {
export type CandyMachineArgs = {
/** Features versioning flags. */
features: number | bigint;
/** Authority address. */
Expand All @@ -87,7 +77,7 @@ export type CandyMachineAccountDataArgs = {
data: CandyMachineDataArgs;
};

export function getCandyMachineAccountDataEncoder(): Encoder<CandyMachineAccountDataArgs> {
export function getCandyMachineEncoder(): Encoder<CandyMachineArgs> {
return transformEncoder(
getStructEncoder([
['discriminator', getArrayEncoder(getU8Encoder(), { size: 8 })],
Expand All @@ -105,7 +95,7 @@ export function getCandyMachineAccountDataEncoder(): Encoder<CandyMachineAccount
);
}

export function getCandyMachineAccountDataDecoder(): Decoder<CandyMachineAccountData> {
export function getCandyMachineDecoder(): Decoder<CandyMachine> {
return getStructDecoder([
['discriminator', getArrayDecoder(getU8Decoder(), { size: 8 })],
['features', getU64Decoder()],
Expand All @@ -117,36 +107,30 @@ export function getCandyMachineAccountDataDecoder(): Decoder<CandyMachineAccount
]);
}

export function getCandyMachineAccountDataCodec(): Codec<
CandyMachineAccountDataArgs,
CandyMachineAccountData
> {
return combineCodec(
getCandyMachineAccountDataEncoder(),
getCandyMachineAccountDataDecoder()
);
export function getCandyMachineCodec(): Codec<CandyMachineArgs, CandyMachine> {
return combineCodec(getCandyMachineEncoder(), getCandyMachineDecoder());
}

export function decodeCandyMachine<TAddress extends string = string>(
encodedAccount: EncodedAccount<TAddress>
): CandyMachine<TAddress>;
): Account<CandyMachine, TAddress>;
export function decodeCandyMachine<TAddress extends string = string>(
encodedAccount: MaybeEncodedAccount<TAddress>
): MaybeCandyMachine<TAddress>;
): MaybeAccount<CandyMachine, TAddress>;
export function decodeCandyMachine<TAddress extends string = string>(
encodedAccount: EncodedAccount<TAddress> | MaybeEncodedAccount<TAddress>
): CandyMachine<TAddress> | MaybeCandyMachine<TAddress> {
): Account<CandyMachine, TAddress> | MaybeAccount<CandyMachine, TAddress> {
return decodeAccount(
encodedAccount as MaybeEncodedAccount<TAddress>,
getCandyMachineAccountDataDecoder()
getCandyMachineDecoder()
);
}

export async function fetchCandyMachine<TAddress extends string = string>(
rpc: Parameters<typeof fetchEncodedAccount>[0],
address: Address<TAddress>,
config?: FetchAccountConfig
): Promise<CandyMachine<TAddress>> {
): Promise<Account<CandyMachine, TAddress>> {
const maybeAccount = await fetchMaybeCandyMachine(rpc, address, config);
assertAccountExists(maybeAccount);
return maybeAccount;
Expand All @@ -156,7 +140,7 @@ export async function fetchMaybeCandyMachine<TAddress extends string = string>(
rpc: Parameters<typeof fetchEncodedAccount>[0],
address: Address<TAddress>,
config?: FetchAccountConfig
): Promise<MaybeCandyMachine<TAddress>> {
): Promise<MaybeAccount<CandyMachine, TAddress>> {
const maybeAccount = await fetchEncodedAccount(rpc, address, config);
return decodeCandyMachine(maybeAccount);
}
Expand All @@ -165,7 +149,7 @@ export async function fetchAllCandyMachine(
rpc: Parameters<typeof fetchEncodedAccounts>[0],
addresses: Array<Address>,
config?: FetchAccountsConfig
): Promise<CandyMachine[]> {
): Promise<Account<CandyMachine>[]> {
const maybeAccounts = await fetchAllMaybeCandyMachine(rpc, addresses, config);
assertAccountsExist(maybeAccounts);
return maybeAccounts;
Expand All @@ -175,7 +159,7 @@ export async function fetchAllMaybeCandyMachine(
rpc: Parameters<typeof fetchEncodedAccounts>[0],
addresses: Array<Address>,
config?: FetchAccountsConfig
): Promise<MaybeCandyMachine[]> {
): Promise<MaybeAccount<CandyMachine>[]> {
const maybeAccounts = await fetchEncodedAccounts(rpc, addresses, config);
return maybeAccounts.map((maybeAccount) => decodeCandyMachine(maybeAccount));
}
Loading
Loading