Skip to content

Commit

Permalink
wip: add CS guards, add freeze guards
Browse files Browse the repository at this point in the history
  • Loading branch information
nhanphan committed Mar 2, 2024
1 parent 6a23e2c commit 8189c2a
Show file tree
Hide file tree
Showing 35 changed files with 1,851 additions and 1,358 deletions.
14 changes: 14 additions & 0 deletions clients/js/src/defaultGuards/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,16 @@ import {
NftBurnArgs,
NftGate,
NftGateArgs,
NftMintLimit,
NftMintLimitArgs,
NftPayment,
NftPaymentArgs,
ProgramGate,
ProgramGateArgs,
RedeemedAmount,
RedeemedAmountArgs,
SolFixedFee,
SolFixedFeeArgs,
SolPayment,
SolPaymentArgs,
StartDate,
Expand Down Expand Up @@ -70,6 +74,8 @@ import { Token2022PaymentMintArgs } from './token2022Payment';
import { TokenBurnMintArgs } from './tokenBurn';
import { TokenGateMintArgs } from './tokenGate';
import { TokenPaymentMintArgs } from './tokenPayment';
import { SolFixedFeeMintArgs } from './solFixedFee';
import { NftMintLimitMintArgs } from './nftMintLimit';

/**
* The arguments for all default Candy Machine guards.
Expand All @@ -96,6 +102,8 @@ export type DefaultGuardSetArgs = GuardSetArgs & {
programGate: OptionOrNullable<ProgramGateArgs>;
allocation: OptionOrNullable<AllocationArgs>;
token2022Payment: OptionOrNullable<Token2022PaymentArgs>;
solFixedFee: OptionOrNullable<SolFixedFeeArgs>;
nftMintLimit: OptionOrNullable<NftMintLimitArgs>;
};

/**
Expand Down Expand Up @@ -123,6 +131,8 @@ export type DefaultGuardSet = GuardSet & {
programGate: Option<ProgramGate>;
allocation: Option<Allocation>;
token2022Payment: Option<Token2022Payment>;
solFixedFee: Option<SolFixedFee>;
nftMintLimit: Option<NftMintLimit>;
};

/**
Expand Down Expand Up @@ -150,6 +160,8 @@ export type DefaultGuardSetMintArgs = GuardSetMintArgs & {
// programGate: no mint settings
allocation: OptionOrNullable<AllocationMintArgs>;
token2022Payment: OptionOrNullable<Token2022PaymentMintArgs>;
solFixedFee: OptionOrNullable<SolFixedFeeMintArgs>;
nftMintLimit: OptionOrNullable<NftMintLimitMintArgs>;
};

/**
Expand Down Expand Up @@ -202,6 +214,8 @@ export const defaultCandyGuardNames: string[] = [
'programGate',
'allocation',
'token2022Payment',
'solFixedFee',
'nftMintLimit',
];

/** @internal */
Expand Down
78 changes: 8 additions & 70 deletions clients/js/src/defaultGuards/freezeSolPayment.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,10 @@
import {
TokenStandard,
findMasterEditionPda,
findMetadataPda,
findTokenRecordPda,
getMplTokenMetadataProgramId,
isProgrammable,
} from '@metaplex-foundation/mpl-token-metadata';
import {
findAssociatedTokenPda,
getSplAssociatedTokenProgramId,
getSplSystemProgramId,
getSplTokenProgramId,
getSysvar,
} from '@metaplex-foundation/mpl-toolbox';
import { PublicKey, Signer } from '@metaplex-foundation/umi';
import { tuple, u64 } from '@metaplex-foundation/umi/serializers';
import { getMplCoreProgramId } from '@metaplex-foundation/mpl-core';
import { UnrecognizePathForRouteInstructionError } from '../errors';
import {
FreezeInstruction,
Expand All @@ -25,7 +15,6 @@ import {
getFreezeSolPaymentSerializer,
} from '../generated';
import { GuardManifest, GuardRemainingAccount, RouteParser } from '../guards';
import { getMplTokenAuthRulesProgramId } from '../programs';

/**
* The freezeSolPayment guard allows minting frozen NFTs by charging
Expand Down Expand Up @@ -169,16 +158,10 @@ export type FreezeSolPaymentRouteArgsThaw = Omit<
path: 'thaw';

/** The mint address of the NFT to thaw. */
nftMint: PublicKey;
asset: PublicKey;

/** The owner address of the NFT to thaw. */
nftOwner: PublicKey;

/** The token standard of the minted NFT. */
nftTokenStandard: TokenStandard;

/** The ruleSet of the minted NFT, if any. */
nftRuleSet?: PublicKey;
owner: PublicKey;
};

/**
Expand Down Expand Up @@ -237,63 +220,18 @@ const thawRouteInstruction: RouteParser<FreezeSolPaymentRouteArgsThaw> = (
candyMachine: routeContext.candyMachine,
candyGuard: routeContext.candyGuard,
});
const [nftFreezeAta] = findAssociatedTokenPda(context, {
mint: args.nftMint,
owner: freezeEscrow,
});
const [nftAta] = findAssociatedTokenPda(context, {
mint: args.nftMint,
owner: args.nftOwner,
});
const [nftMetadata] = findMetadataPda(context, { mint: args.nftMint });
const [nftEdition] = findMasterEditionPda(context, { mint: args.nftMint });
const [nftAtaTokenRecord] = findTokenRecordPda(context, {
mint: args.nftMint,
token: nftAta,
});
const [nftFreezeAtaTokenRecord] = findTokenRecordPda(context, {
mint: args.nftMint,
token: nftFreezeAta,
});

const data = getFreezeInstructionSerializer().serialize(
FreezeInstruction.Thaw
);
const remainingAccounts: GuardRemainingAccount[] = [
{ publicKey: freezeEscrow, isWritable: true },
{ publicKey: args.nftMint, isWritable: false },
{ publicKey: args.nftOwner, isWritable: false },
{ publicKey: nftAta, isWritable: true },
{ publicKey: nftEdition, isWritable: false },
{ publicKey: getSplTokenProgramId(context), isWritable: false },
{ publicKey: getMplTokenMetadataProgramId(context), isWritable: false },
{ publicKey: args.asset, isWritable: true },
{ publicKey: args.owner, isWritable: false },
{ publicKey: getMplCoreProgramId(context), isWritable: false },
{ publicKey: getSplSystemProgramId(context), isWritable: false },
];

if (!isProgrammable(args.nftTokenStandard)) {
return { data, remainingAccounts };
}

remainingAccounts.push(
...[
{ publicKey: nftMetadata, isWritable: true },
{ publicKey: nftFreezeAta, isWritable: true },
{ publicKey: getSplSystemProgramId(context), isWritable: false },
{ publicKey: getSysvar('instructions'), isWritable: false },
{ publicKey: getSplAssociatedTokenProgramId(context), isWritable: false },
{ publicKey: nftAtaTokenRecord, isWritable: true },
{ publicKey: nftFreezeAtaTokenRecord, isWritable: true },
]
);

if (args.nftRuleSet) {
const tokenAuthRules = getMplTokenAuthRulesProgramId(context);
remainingAccounts.push(
...[
{ publicKey: tokenAuthRules, isWritable: false },
{ publicKey: args.nftRuleSet, isWritable: false },
]
);
}

return { data, remainingAccounts };
};

Expand Down
75 changes: 7 additions & 68 deletions clients/js/src/defaultGuards/freezeTokenPayment.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,12 @@
import {
TokenStandard,
findMasterEditionPda,
findMetadataPda,
findTokenRecordPda,
getMplTokenMetadataProgramId,
isProgrammable,
} from '@metaplex-foundation/mpl-token-metadata';
import {
findAssociatedTokenPda,
getSplAssociatedTokenProgramId,
getSplSystemProgramId,
getSplTokenProgramId,
getSysvar,
} from '@metaplex-foundation/mpl-toolbox';
import { PublicKey, Signer } from '@metaplex-foundation/umi';
import { tuple, u64 } from '@metaplex-foundation/umi/serializers';
import { getMplCoreProgramId } from '@metaplex-foundation/mpl-core';
import { UnrecognizePathForRouteInstructionError } from '../errors';
import {
FreezeInstruction,
Expand All @@ -25,7 +17,6 @@ import {
getFreezeTokenPaymentSerializer,
} from '../generated';
import { GuardManifest, GuardRemainingAccount, RouteParser } from '../guards';
import { getMplTokenAuthRulesProgramId } from '../programs';

/**
* The freezeTokenPayment guard allows minting frozen NFTs by charging
Expand Down Expand Up @@ -181,16 +172,10 @@ export type FreezeTokenPaymentRouteArgsThaw = Omit<
path: 'thaw';

/** The mint address of the NFT to thaw. */
nftMint: PublicKey;
asset: PublicKey;

/** The owner address of the NFT to thaw. */
nftOwner: PublicKey;

/** The token standard of the minted NFT. */
nftTokenStandard: TokenStandard;

/** The ruleSet of the minted NFT, if any. */
nftRuleSet?: PublicKey;
owner: PublicKey;
};

/**
Expand Down Expand Up @@ -259,63 +244,17 @@ const thawRouteInstruction: RouteParser<FreezeTokenPaymentRouteArgsThaw> = (
candyMachine: routeContext.candyMachine,
candyGuard: routeContext.candyGuard,
});
const [nftFreezeAta] = findAssociatedTokenPda(context, {
mint: args.nftMint,
owner: freezeEscrow,
});
const [nftAta] = findAssociatedTokenPda(context, {
mint: args.nftMint,
owner: args.nftOwner,
});
const [nftMetadata] = findMetadataPda(context, { mint: args.nftMint });
const [nftEdition] = findMasterEditionPda(context, { mint: args.nftMint });
const [nftAtaTokenRecord] = findTokenRecordPda(context, {
mint: args.nftMint,
token: nftAta,
});
const [nftFreezeAtaTokenRecord] = findTokenRecordPda(context, {
mint: args.nftMint,
token: nftFreezeAta,
});
const data = getFreezeInstructionSerializer().serialize(
FreezeInstruction.Thaw
);
const remainingAccounts: GuardRemainingAccount[] = [
{ publicKey: freezeEscrow, isWritable: true },
{ publicKey: args.nftMint, isWritable: false },
{ publicKey: args.nftOwner, isWritable: false },
{ publicKey: nftAta, isWritable: true },
{ publicKey: nftEdition, isWritable: false },
{ publicKey: getSplTokenProgramId(context), isWritable: false },
{ publicKey: getMplTokenMetadataProgramId(context), isWritable: false },
{ publicKey: args.asset, isWritable: true },
{ publicKey: args.owner, isWritable: false },
{ publicKey: getMplCoreProgramId(context), isWritable: false },
{ publicKey: getSplSystemProgramId(context), isWritable: false },
];

if (!isProgrammable(args.nftTokenStandard)) {
return { data, remainingAccounts };
}

remainingAccounts.push(
...[
{ publicKey: nftMetadata, isWritable: true },
{ publicKey: nftFreezeAta, isWritable: true },
{ publicKey: getSplSystemProgramId(context), isWritable: false },
{ publicKey: getSysvar('instructions'), isWritable: false },
{ publicKey: getSplAssociatedTokenProgramId(context), isWritable: false },
{ publicKey: nftAtaTokenRecord, isWritable: true },
{ publicKey: nftFreezeAtaTokenRecord, isWritable: true },
]
);

if (args.nftRuleSet) {
const tokenAuthRules = getMplTokenAuthRulesProgramId(context);
remainingAccounts.push(
...[
{ publicKey: tokenAuthRules, isWritable: false },
{ publicKey: args.nftRuleSet, isWritable: false },
]
);
}

return { data, remainingAccounts };
};

Expand Down
2 changes: 2 additions & 0 deletions clients/js/src/defaultGuards/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ export * from './gatekeeper';
export * from './mintLimit';
export * from './nftBurn';
export * from './nftGate';
export * from './nftMintLimit';
export * from './nftPayment';
export * from './programGate';
export * from './redeemedAmount';
export * from './solFixedFee';
export * from './solPayment';
export * from './startDate';
export * from './thirdPartySigner';
Expand Down
76 changes: 76 additions & 0 deletions clients/js/src/defaultGuards/nftMintLimit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { findAssociatedTokenPda } from '@metaplex-foundation/mpl-toolbox';
import { findMetadataPda } from '@metaplex-foundation/mpl-token-metadata';
import { PublicKey } from '@metaplex-foundation/umi';
import {
findNftMintCounterPda,
getNftMintLimitSerializer,
NftMintLimit,
NftMintLimitArgs,
} from '../generated';
import { GuardManifest, noopParser } from '../guards';

/**
* The nftMintLimit guard allows to specify a limit on the
* number of mints for a specific NFT mint.
*
* The limit is set per NFT mint, per candy machine and per
* identified (provided in the settings) to allow multiple
* NFT mint limits within a Candy Machine. This is particularly
* useful when using groups of guards and we want each of them
* to have a different NFT mint limit.
*/
export const nftMintLimitGuardManifest: GuardManifest<
NftMintLimitArgs,
NftMintLimit,
NftMintLimitMintArgs
> = {
name: 'nftMintLimit',
serializer: getNftMintLimitSerializer,
mintParser: (context, mintContext, args) => {
const tokenAccount =
args.tokenAccount ??
findAssociatedTokenPda(context, {
mint: args.mint,
owner: mintContext.minter.publicKey,
})[0];
const [tokenMetadata] = findMetadataPda(context, { mint: args.mint });
const [mintCounter] = findNftMintCounterPda(context, {
id: args.id,
mint: args.mint,
candyMachine: mintContext.candyMachine,
candyGuard: mintContext.candyGuard,
});

return {
data: new Uint8Array(),
remainingAccounts: [
{ publicKey: mintCounter, isWritable: true },
{ publicKey: tokenAccount, isWritable: false },
{ publicKey: tokenMetadata, isWritable: false },
],
};
},
routeParser: noopParser,
};

export type NftMintLimitMintArgs = {
/**
* The id of the NFT mint limit.
*/
id: number;

/**
* The mint address of an NFT from the required
* collection that belongs to the minter.
*/
mint: PublicKey;

/**
* The token account linking the NFT with its owner.
*
* @defaultValue
* Defaults to the associated token address using the
* mint address of the NFT and the minter's address.
*/
tokenAccount?: PublicKey;
};
Loading

0 comments on commit 8189c2a

Please sign in to comment.