@silvana-one/nft
Version:
Mina NFT library
580 lines (579 loc) • 28.5 kB
TypeScript
/**
* The NFT Collection Contract is responsible for managing a collection of NFTs.
* It handles minting new NFTs, transferring ownership, buying, selling,
* and interfacing with Admin Contracts for additional functionalities.
*
* @module CollectionContract
*/
import { Field, PublicKey, AccountUpdate, Bool, State, DeployArgs, AccountUpdateForest, VerificationKey, UInt32, UInt64 } from "o1js";
import { MintParams, MintRequest, TransferBySignatureParams, TransferByProofParams, CollectionData, NFTUpdateProof, NFTStateStruct, MintEvent, NFTUpdateEvent, TransferEvent, ApproveEvent, UpgradeVerificationKeyEvent, LimitMintingEvent, PauseNFTEvent, NFTAdminBase, NFTAdminContractConstructor, PauseEvent, SetNameEvent, SetBaseURLEvent, SetRoyaltyFeeEvent, SetTransferFeeEvent, SetAdminEvent, OwnershipChangeEvent, NFTOwnerBase, NFTOwnerContractConstructor, UpgradeVerificationKeyData, NFTApprovalContractConstructor, NFTApprovalBase, NFTUpdateContractConstructor, NFTUpdateBase, TransferExtendedParams } from "../interfaces/index.js";
export { CollectionDeployProps, CollectionFactory, CollectionErrors };
declare const CollectionErrors: {
wrongMasterNFTaddress: string;
transferNotAllowed: string;
collectionPaused: string;
cannotMintMasterNFT: string;
cannotMint: string;
noPermissionToPause: string;
noPermissionToResume: string;
collectionNotPaused: string;
transferApprovalRequired: string;
noPermissionToChangeName: string;
noPermissionToChangeBaseUri: string;
noPermissionToChangeCreator: string;
noPermissionToChangeRoyalty: string;
noPermissionToChangeTransferFee: string;
noPermissionToSetAdmin: string;
cannotUpgradeVerificationKey: string;
upgradeContractAddressNotSet: string;
adminContractAddressNotSet: string;
onlyOwnerCanUpgradeVerificationKey: string;
invalidRoyaltyFee: string;
invalidOracleAddress: string;
pendingCreatorIsEmpty: string;
};
interface CollectionDeployProps extends Exclude<DeployArgs, undefined> {
collectionName: Field;
creator: PublicKey;
admin: PublicKey;
baseURL: Field;
symbol: string;
url: string;
}
/**
* Creates a new NFT Collection Contract class.
*
* @param params - Constructor parameters including admin and upgrade contracts, and network ID.
* @returns The Collection class extending TokenContract and implementing required interfaces.
*/
declare function CollectionFactory(params: {
adminContract: () => NFTAdminContractConstructor;
ownerContract: () => NFTOwnerContractConstructor;
approvalContract: () => NFTApprovalContractConstructor;
updateContract: () => NFTUpdateContractConstructor;
}): {
new (address: PublicKey, tokenId?: Field): {
/** The name of the NFT collection. */
collectionName: State<import("node_modules/o1js/dist/node/lib/provable/field.js").Field>;
/** The public key of the creator of the collection. */
creator: State<PublicKey>;
/** The public key of the Admin Contract. */
admin: State<PublicKey>;
/** The base URL for the metadata of the NFTs in the collection. */
baseURL: State<import("node_modules/o1js/dist/node/lib/provable/field.js").Field>;
/**
* A packed data field containing additional collection parameters,
* such as flags and fee configurations.
*/
packedData: State<import("node_modules/o1js/dist/node/lib/provable/field.js").Field>;
/** The public key part (x) of the pending creator. The isOdd field is written to the packedData */
pendingCreatorX: State<import("node_modules/o1js/dist/node/lib/provable/field.js").Field>;
/**
* Deploys the NFT Collection Contract with the initial settings.
*
* @param props - Deployment properties including collection name, creator, admin, baseURL, symbol, and URL.
*/
deploy(props: CollectionDeployProps): Promise<void>;
/**
* Initializes the collection with a master NFT and initial data.
*
* @param masterNFT - The master NFT parameters.
* @param collectionData - Initial collection data including flags and configurations.
*/
initialize(masterNFT: MintParams, collectionData: CollectionData): Promise<void>;
/**
* Defines the events emitted by the contract.
*/
events: {
mint: typeof MintEvent;
update: typeof NFTUpdateEvent;
transfer: typeof TransferEvent;
approve: typeof ApproveEvent;
upgradeNFTVerificationKey: typeof UpgradeVerificationKeyEvent;
upgradeVerificationKey: typeof UpgradeVerificationKeyEvent;
limitMinting: typeof LimitMintingEvent;
pause: typeof PauseEvent;
resume: typeof PauseEvent;
pauseNFT: typeof PauseNFTEvent;
resumeNFT: typeof PauseNFTEvent;
ownershipTransfer: typeof OwnershipChangeEvent;
ownershipAccepted: typeof OwnershipChangeEvent;
setName: typeof SetNameEvent;
setBaseURL: typeof SetBaseURLEvent;
setRoyaltyFee: typeof SetRoyaltyFeeEvent;
setTransferFee: typeof SetTransferFeeEvent;
setAdmin: typeof SetAdminEvent;
};
/**
* Overrides the approveBase method to prevent transfers of tokens.
*
* @param forest - The account update forest.
*/
approveBase(forest: AccountUpdateForest): Promise<void>;
/**
* Retrieves the Admin Contract instance.
*
* @returns The Admin Contract instance implementing NFTAdminBase.
*/
getAdminContract(): NFTAdminBase;
/**
* Retrieves the NFT Owner Contract instance.
*
* @returns The Owner Contract instance implementing NFTOwnerBase.
*/
getOwnerContract(address: PublicKey): NFTOwnerBase;
/**
* Retrieves the NFT Approval Contract instance.
*
* @returns The Approval Contract instance implementing NFTApprovalBase.
*/
getApprovalContract(address: PublicKey): NFTApprovalBase;
/**
* Retrieves the NFT Update Contract instance.
*
* @returns The Update Contract instance implementing NFTUpdateBase.
*/
getUpdateContract(address: PublicKey): NFTUpdateBase;
/**
* Ensures that the transaction is authorized by the creator.
*
* @returns The AccountUpdate of the creator.
*/
ensureCreatorSignature(): Promise<AccountUpdate>;
/**
* Ensures that the transaction is authorized by the NFT owner
*
* @returns The AccountUpdate of the NFT owner.
*/
ensureOwnerSignature(owner: PublicKey): Promise<AccountUpdate>;
/**
* Ensures that the collection is not paused.
*
* @returns The packed data of the collection.
*/
ensureNotPaused(): Promise<CollectionData>;
/**
* Mints a new NFT directly by the creator.
*
* This method allows the creator of the collection to mint an NFT without requiring approval
* from the admin contract. It ensures that the collection is not paused and that the caller
* is the creator of the collection. A fee of 1 MINA is deducted from the creator's balance
* to cover the cost of creating a new account.
*
* We do not constrain here the address of the NFT to allow for the Master NFT to be minted.
* The Master NFT is the NFT with the same address as the Collection contract and it holds
* the metadata for the collection. It can be minted only by the creator of the collection.
*
* @param params - The mint parameters containing details of the NFT to be minted.
*/
mintByCreator(params: MintParams): Promise<void>;
/**
* Mints a new NFT with approval.
*
* @param mintRequest - The minting request containing parameters and proofs.
*/
mint(mintRequest: MintRequest): Promise<void>;
/**
* Internal method to mint an NFT.
*
* @param params - The mint parameters.
* @param collectionData - The current collection data.
* @returns The MintEvent emitted.
*/
_mint(params: MintParams): Promise<MintEvent>;
/**
* Updates the NFT with admin approval.
*
* @param proof - The proof of the NFT update.
* @param vk - The verification key.
*/
update(proof: NFTUpdateProof, vk: VerificationKey): Promise<void>;
/**
* Updates the NFT with admin approval and oracle approval.
*
* @param proof - The proof of the NFT update.
* @param vk - The verification key.
*/
updateWithOracle(proof: NFTUpdateProof, vk: VerificationKey): Promise<void>;
/**
* Updates the NFT with admin approval - internal method.
*
* @param proof - The proof of the NFT update.
* @param vk - The verification key.
*/
_update(proof: NFTUpdateProof, vk: VerificationKey): Promise<void>;
/**
* Approves an address to transfer an NFT.
*
* @param nftAddress - The address of the NFT.
* @param approved - The approved public key.
*/
approveAddress(nftAddress: PublicKey, approved: PublicKey): Promise<void>;
/**
* Transfers ownership of an NFT without admin approval.
*
* @param nftAddress - The address of the NFT.
* @param approved - The approved public key.
*/
approveAddressByProof(nftAddress: PublicKey, approved: PublicKey): Promise<void>;
/**
* Transfers ownership of an NFT without admin approval.
* This method should be used by wallets for collections that do not require transfer approval
* and the owners of the NFTs which approve the transfer by signature
*
* @param address - The address of the NFT.
* @param to - The recipient's public key.
* @param price - The price of the NFT (optional).
*/
transferBySignature(params: TransferBySignatureParams): Promise<void>;
/**
* Transfers ownership of an NFT using a proof in case the owner is a contract
* Can be called by the owner or approved that should be a contracts
* supporting NFTApprovalBase interface
*
* @param params - The transfer parameters.
*/
transferByProof(params: TransferByProofParams): Promise<void>;
/**
* Transfers ownership of an NFT using a proof in case the owner is a contract
* Can be called by the owner or approved that should be a contracts
* supporting NFTApprovalBase interface
*
* @param params - The transfer parameters.
*/
adminApprovedTransferByProof(params: TransferByProofParams): Promise<void>;
/**
* Transfers ownership of an NFT with admin approval.
*
* @param address - The address of the NFT.
* @param to - The recipient's public key.
* @param price - The price of the NFT (optional).
*/
adminApprovedTransferBySignature(params: TransferBySignatureParams): Promise<void>;
/**
* Internal method to transfer an NFT.
*
* This method handles the transfer logic and fee calculation. The fee is determined as follows:
* - If a price is provided, the fee is calculated as (price * royaltyFee / MAX_ROYALTY_FEE)
* - If no price is provided, the fixed transferFee is used to handle two cases:
* when NFT is being sold and the price is not provided to the contract
* when NFT is being transferred by the owner (without price)
* - If the sender is the creator, no fee is charged
* - The minimum fee is always the transferFee (unless sender is creator)
*
* @param transferEventDraft - The transfer event draft, containing the information about the transfer
* @param transferFee - The transfer fee amount.
* @param royaltyFee - The royalty fee amount.
* @returns The TransferEvent emitted.
*/
_transfer(params: {
transferEventDraft: TransferExtendedParams;
transferFee: UInt64;
royaltyFee: UInt32;
}): Promise<TransferExtendedParams>;
/**
* Upgrades the verification key of a specific NFT.
*
* @param address - The address of the NFT.
* @param vk - The new verification key.
*/
upgradeNFTVerificationKeyBySignature(address: PublicKey, vk: VerificationKey): Promise<void>;
/**
* Upgrades the verification key of a specific NFT by Proof.
*
* @param address - The address of the NFT.
* @param vk - The new verification key.
*/
upgradeNFTVerificationKeyByProof(address: PublicKey, vk: VerificationKey): Promise<void>;
_upgrade(address: PublicKey, vk: VerificationKey): Promise<UpgradeVerificationKeyData>;
/**
* Upgrades the verification key of the collection contract.
*
* @param vk - The new verification key.
*/
upgradeVerificationKey(vk: VerificationKey): Promise<void>;
/**
* Limits further minting of NFTs in the collection.
*/
limitMinting(): Promise<void>;
/**
* Pauses the collection, disabling certain actions.
*/
pause(): Promise<void>;
/**
* Resumes the collection, re-enabling actions.
*/
resume(): Promise<void>;
/**
* Pauses a specific NFT, disabling its actions.
*
* @param address - The address of the NFT to pause.
*/
pauseNFTBySignature(address: PublicKey): Promise<void>;
/**
* Pauses a specific NFT, disabling its actions.
*
* @param address - The address of the NFT to pause.
*/
pauseNFTByProof(address: PublicKey): Promise<void>;
/**
* Resumes a specific NFT, re-enabling its actions.
*
* @param address - The address of the NFT to resume.
*/
resumeNFT(address: PublicKey): Promise<void>;
/**
* Resumes a specific NFT, re-enabling its actions.
*
* @param address - The address of the NFT to resume.
*/
resumeNFTByProof(address: PublicKey): Promise<void>;
/**
* Sets a new name for the collection.
* Requires owner signature and collection to not be paused.
* Emits a 'setName' event with the new name.
*
* @param name - The new name for the collection as a Field value
* @throws {Error} If caller lacks permission to change name
*/
setName(name: Field): Promise<void>;
/**
* Updates the base URL for the collection's metadata.
* Requires owner signature and collection to not be paused.
* Emits a 'setBaseURL' event with the new URL.
*
* @param baseURL - The new base URL as a Field value
* @throws {Error} If caller lacks permission to change base URI
*/
setBaseURL(baseURL: Field): Promise<void>;
/**
* Sets a new admin address for the collection.
* Requires owner signature and collection to not be paused.
* Emits a 'setAdmin' event with the new admin address.
*
* @param admin - The public key of the new admin
* @throws {Error} If caller lacks permission to set admin
*/
setAdmin(admin: PublicKey): Promise<void>;
/**
* Updates the royalty fee for the collection.
* Requires owner signature and collection to not be paused.
* Emits a 'setRoyaltyFee' event with the new fee.
*
* @param royaltyFee - The new royalty fee as a UInt32 value
* @throws {Error} If caller lacks permission to change royalty fee
*/
setRoyaltyFee(royaltyFee: UInt32): Promise<void>;
/**
* Updates the transfer fee for the collection.
* Requires owner signature and collection to not be paused.
* Emits a 'setTransferFee' event with the new fee.
*
* @param transferFee - The new transfer fee as a UInt64 value
* @throws {Error} If caller lacks permission to change transfer fee
*/
setTransferFee(transferFee: UInt64): Promise<void>;
/**
* Transfers ownership of the collection to a new creator.
* This method is called transferOwnership as the Collection is implementing OwnableContract interface
* For the Collection, the creator is the owner of the collection
*
* @param to - The public key of the new creator.
* @returns The public key of the old creator.
*/
transferOwnership(to: PublicKey): Promise<PublicKey>;
/**
* Transfers ownership of the collection to a new owner.
*
* @param to - The public key of the new owner.
* @returns The public key of the old owner.
*/
acceptOwnership(): Promise<PublicKey>;
getNFTState(address: PublicKey): Promise<NFTStateStruct>;
deriveTokenId(): import("node_modules/o1js/dist/node/lib/provable/field.js").Field;
get internal(): {
mint({ address, amount, }: {
address: PublicKey | AccountUpdate | import("o1js").SmartContract;
amount: number | bigint | UInt64;
}): AccountUpdate;
burn({ address, amount, }: {
address: PublicKey | AccountUpdate | import("o1js").SmartContract;
amount: number | bigint | UInt64;
}): AccountUpdate;
send({ from, to, amount, }: {
from: PublicKey | AccountUpdate | import("o1js").SmartContract;
to: PublicKey | AccountUpdate | import("o1js").SmartContract;
amount: number | bigint | UInt64;
}): AccountUpdate;
};
forEachUpdate(updates: AccountUpdateForest, callback: (update: AccountUpdate, usesToken: Bool) => void): void;
checkZeroBalanceChange(updates: AccountUpdateForest): void;
approveAccountUpdate(accountUpdate: AccountUpdate | import("o1js").AccountUpdateTree): Promise<void>;
approveAccountUpdates(accountUpdates: (AccountUpdate | import("o1js").AccountUpdateTree)[]): Promise<void>;
transfer(from: PublicKey | AccountUpdate, to: PublicKey | AccountUpdate, amount: UInt64 | number | bigint): Promise<void>;
"__#private@#private": any;
address: PublicKey;
tokenId: Field;
init(): void;
requireSignature(): void;
skipAuthorization(): void;
get self(): AccountUpdate;
newSelf(methodName?: string): AccountUpdate;
sender: {
self: import("o1js").SmartContract;
getUnconstrained(): PublicKey;
getAndRequireSignature(): PublicKey;
};
get account(): import("node_modules/o1js/dist/node/lib/mina/v1/precondition.js").Account;
get network(): import("node_modules/o1js/dist/node/lib/mina/v1/precondition.js").Network;
get currentSlot(): import("node_modules/o1js/dist/node/lib/mina/v1/precondition.js").CurrentSlot;
approve(update: AccountUpdate | import("o1js").AccountUpdateTree | AccountUpdateForest): void;
send(args: {
to: PublicKey | AccountUpdate | import("o1js").SmartContract;
amount: number | bigint | UInt64;
}): AccountUpdate;
get balance(): {
addInPlace(x: string | number | bigint | UInt64 | UInt32 | import("o1js").Int64): void;
subInPlace(x: string | number | bigint | UInt64 | UInt32 | import("o1js").Int64): void;
};
emitEventIf<K extends "update" | "approve" | "transfer" | "upgradeVerificationKey" | "pause" | "resume" | "mint" | "upgradeNFTVerificationKey" | "limitMinting" | "pauseNFT" | "resumeNFT" | "ownershipTransfer" | "ownershipAccepted" | "setName" | "setBaseURL" | "setRoyaltyFee" | "setTransferFee" | "setAdmin">(condition: Bool, type: K, event: any): void;
emitEvent<K extends "update" | "approve" | "transfer" | "upgradeVerificationKey" | "pause" | "resume" | "mint" | "upgradeNFTVerificationKey" | "limitMinting" | "pauseNFT" | "resumeNFT" | "ownershipTransfer" | "ownershipAccepted" | "setName" | "setBaseURL" | "setRoyaltyFee" | "setTransferFee" | "setAdmin">(type: K, event: any): void;
fetchEvents(start?: UInt32, end?: UInt32): Promise<{
type: string;
event: {
data: import("o1js").ProvablePure<any>;
transactionInfo: {
transactionHash: string;
transactionStatus: string;
transactionMemo: string;
};
};
blockHeight: UInt32;
blockHash: string;
parentBlockHash: string;
globalSlot: UInt32;
chainStatus: string;
}[]>;
};
MAX_ACCOUNT_UPDATES: number;
_methods?: import("node_modules/o1js/dist/node/lib/proof-system/zkprogram.js").MethodInterface[];
_methodMetadata?: Record<string, {
actions: number;
rows: number;
digest: string;
gates: import("node_modules/o1js/dist/node/bindings.js").Gate[];
proofs: import("node_modules/o1js/dist/node/lib/proof-system/proof.js").ProofClass[];
}>;
_provers?: import("node_modules/o1js/dist/node/bindings.js").Pickles.Prover[];
_verificationKey?: {
data: string;
hash: Field;
};
Proof(): {
new ({ proof, publicInput, publicOutput, maxProofsVerified, }: {
proof: unknown;
publicInput: import("o1js").ZkappPublicInput;
publicOutput: undefined;
maxProofsVerified: 0 | 2 | 1;
}): {
verify(): void;
verifyIf(condition: import("node_modules/o1js/dist/node/lib/provable/bool.js").Bool): void;
publicInput: import("o1js").ZkappPublicInput;
publicOutput: undefined;
proof: unknown;
maxProofsVerified: 0 | 2 | 1;
shouldVerify: import("node_modules/o1js/dist/node/lib/provable/bool.js").Bool;
declare(): boolean;
toJSON(): import("o1js").JsonProof;
publicFields(): {
input: import("node_modules/o1js/dist/node/lib/provable/field.js").Field[];
output: import("node_modules/o1js/dist/node/lib/provable/field.js").Field[];
};
};
publicInputType: Omit<import("node_modules/o1js/dist/node/lib/provable/types/provable-intf.js").Provable<{
accountUpdate: import("node_modules/o1js/dist/node/lib/provable/field.js").Field;
calls: import("node_modules/o1js/dist/node/lib/provable/field.js").Field;
}, {
accountUpdate: bigint;
calls: bigint;
}>, "fromFields"> & {
fromFields: (fields: import("node_modules/o1js/dist/node/lib/provable/field.js").Field[]) => {
accountUpdate: import("node_modules/o1js/dist/node/lib/provable/field.js").Field;
calls: import("node_modules/o1js/dist/node/lib/provable/field.js").Field;
};
} & {
toInput: (x: {
accountUpdate: import("node_modules/o1js/dist/node/lib/provable/field.js").Field;
calls: import("node_modules/o1js/dist/node/lib/provable/field.js").Field;
}) => {
fields?: import("node_modules/o1js/dist/node/lib/provable/field.js").Field[] | undefined;
packed?: [import("node_modules/o1js/dist/node/lib/provable/field.js").Field, number][] | undefined;
};
toJSON: (x: {
accountUpdate: import("node_modules/o1js/dist/node/lib/provable/field.js").Field;
calls: import("node_modules/o1js/dist/node/lib/provable/field.js").Field;
}) => {
accountUpdate: string;
calls: string;
};
fromJSON: (x: {
accountUpdate: string;
calls: string;
}) => {
accountUpdate: import("node_modules/o1js/dist/node/lib/provable/field.js").Field;
calls: import("node_modules/o1js/dist/node/lib/provable/field.js").Field;
};
empty: () => {
accountUpdate: import("node_modules/o1js/dist/node/lib/provable/field.js").Field;
calls: import("node_modules/o1js/dist/node/lib/provable/field.js").Field;
};
};
publicOutputType: import("o1js").ProvablePureExtended<undefined, undefined, null>;
tag: () => typeof import("o1js").SmartContract;
fromJSON<S extends import("node_modules/o1js/dist/node/lib/util/types.js").Subclass<typeof import("o1js").Proof>>(this: S, { maxProofsVerified, proof: proofString, publicInput: publicInputJson, publicOutput: publicOutputJson, }: import("o1js").JsonProof): Promise<import("o1js").Proof<import("o1js").InferProvable<S["publicInputType"]>, import("o1js").InferProvable<S["publicOutputType"]>>>;
dummy<Input, OutPut>(publicInput: Input, publicOutput: OutPut, maxProofsVerified: 0 | 2 | 1, domainLog2?: number): Promise<import("o1js").Proof<Input, OutPut>>;
readonly provable: {
toFields: (value: import("o1js").Proof<any, any>) => import("node_modules/o1js/dist/node/lib/provable/field.js").Field[];
toAuxiliary: (value?: import("o1js").Proof<any, any> | undefined) => any[];
fromFields: (fields: import("node_modules/o1js/dist/node/lib/provable/field.js").Field[], aux: any[]) => import("o1js").Proof<any, any>;
sizeInFields(): number;
check: (value: import("o1js").Proof<any, any>) => void;
toValue: (x: import("o1js").Proof<any, any>) => import("node_modules/o1js/dist/node/lib/proof-system/proof.js").ProofValue<any, any>;
fromValue: (x: import("o1js").Proof<any, any> | import("node_modules/o1js/dist/node/lib/proof-system/proof.js").ProofValue<any, any>) => import("o1js").Proof<any, any>;
toCanonical?: ((x: import("o1js").Proof<any, any>) => import("o1js").Proof<any, any>) | undefined;
};
publicFields(value: import("o1js").ProofBase<any, any>): {
input: import("node_modules/o1js/dist/node/lib/provable/field.js").Field[];
output: import("node_modules/o1js/dist/node/lib/provable/field.js").Field[];
};
_proofFromBase64(proofString: string, maxProofsVerified: 0 | 2 | 1): unknown;
_proofToBase64(proof: unknown, maxProofsVerified: 0 | 2 | 1): string;
};
compile({ cache, forceRecompile }?: {
cache?: import("o1js").Cache | undefined;
forceRecompile?: boolean | undefined;
}): Promise<{
verificationKey: {
data: string;
hash: import("node_modules/o1js/dist/node/lib/provable/field.js").Field;
};
provers: import("node_modules/o1js/dist/node/bindings.js").Pickles.Prover[];
verify: (statement: import("node_modules/o1js/dist/node/bindings.js").Pickles.Statement<import("node_modules/o1js/dist/node/lib/provable/core/fieldvar.js").FieldConst>, proof: unknown) => Promise<boolean>;
}>;
digest(): Promise<string>;
getMaxProofsVerified(): Promise<0 | 2 | 1>;
setVerificationKeyUnsafe(verificationKey: {
data: string;
hash: Field | string;
}): void;
runOutsideCircuit(run: () => void): void;
analyzeMethods({ printSummary }?: {
printSummary?: boolean | undefined;
}): Promise<Record<string, {
actions: number;
rows: number;
digest: string;
gates: import("node_modules/o1js/dist/node/bindings.js").Gate[];
proofs: import("node_modules/o1js/dist/node/lib/proof-system/proof.js").ProofClass[];
}>>;
};