Skip to content

Contract Client Reference

Complete reference for apps/emprops-studio/clients/contract-client.ts - the core NFT contract interaction layer.

Overview

The contract client is a ~1,270 line TypeScript module that handles all blockchain interactions for NFT collections. It supports:

  • Tezos (FA2) - Production
  • Ethereum (ERC721) - Development
  • Base (ERC721) - Development

Type Definitions

Blockchain Types

typescript
type Blockchain = "TEZOS" | "ETHEREUM" | "BASE"

type TezosCollectionKey = "projects" | "collections"

Collection Configuration

typescript
interface CollectionContractConfig {
  price: number       // Native token units
  editions: number    // Max supply
  status: "ON" | "OFF"
}

Receiver (Revenue Split)

typescript
interface Receiver {
  part_account: string  // Wallet address
  part_value: number    // Basis points (10000 = 100%)
}

Mint Modes

typescript
// Tezos V1 (Projects)
enum MintMode {
  ALLOWLIST = 0,
  FREELIST = 1,
  ALL = 2
}

// Tezos V2 (Collections)
enum CollectionMintMode {
  PUBLIC = 0,
  ALLOW_LIST = 1,
  FREE_LIST = 2
}

// Contract Status
enum Status {
  OFF = 0,
  ON = 1
}

Collection Reading Functions

getTezCollection()

Fetches on-chain collection configuration from Tezos.

typescript
async function getTezCollection(
  project: Project
): Promise<CollectionContractConfig | null>

Parameters:

  • project - Project object with mintingContractAddress and ID

Returns:

typescript
{
  status: "ON" | "OFF",
  editions: number,
  price: number  // In XTZ (converted from mutez)
}

Implementation Details:

  1. Creates read-only TezosToolkit via getQuerierClientTez()
  2. Loads contract at project.mintingContractAddress
  3. Detects version via getTezCollectionKey()
  4. V1: Queries storage.projects.get(project.id)
  5. V2: Queries storage.collections.get(project.projectId)
  6. Converts price from mutez to XTZ

getEthCollection()

Fetches on-chain collection configuration from Ethereum/Base.

typescript
async function getEthCollection(
  project: Project
): Promise<CollectionContractConfig | null>

Parameters:

  • project - Project object with blockchain info

Returns:

typescript
{
  status: "ON" | "OFF",
  editions: number,
  price: number  // In ETH
}

Implementation Details:

  1. Selects RPC based on project.blockchain
  2. Creates Viem public client
  3. Reads contract state via readContract()
  4. Converts price from wei to ETH

Collection Update Functions

updateTezCollectionStatus()

Toggle minting on/off for Tezos collection.

typescript
async function updateTezCollectionStatus(
  collection: Collection,
  wallet: TezosToolkit,
  newStatus: "ON" | "OFF"
): Promise<void>

Contract Calls:

  • V1: contract.methodsObject.set_status(project_id, status)
  • V2: contract.methodsObject.setStatus(collection_id, status)

updateTezCollectionPrice()

Update mint price for Tezos collection.

typescript
async function updateTezCollectionPrice(
  collection: Collection,
  wallet: TezosToolkit,
  newPrice: number  // In XTZ
): Promise<void>

Contract Calls:

  • V1: contract.methodsObject.set_price(project_id, price_mutez)
  • V2: contract.methodsObject.setPrice(collection_id, price_mutez)

Note: Price is converted to mutez: newPrice * 1_000_000

updateTezCollectionEditions()

Update max supply for Tezos collection.

typescript
async function updateTezCollectionEditions(
  collection: Collection,
  wallet: TezosToolkit,
  newEditions: number
): Promise<void>

Contract Calls:

  • V1: contract.methodsObject.set_total_editions(project_id, editions)
  • V2: contract.methodsObject.setTotalEditions(collection_id, editions)

Fund Redemption Functions

getRedeemableTezFunds()

Calculate available funds for withdrawal.

typescript
async function getRedeemableTezFunds(
  project: Project,
  receiverAddress: string
): Promise<number>  // Returns mutez

Calculation:

  • V1: funds_collected * (creator_percentage / 10000)
  • V2: (funds_collected * part_value / 10000) - funds_claimed

V2 Additional Logic:

  • Queries fundsClaimed BigMap for already withdrawn amounts
  • Subtracts claimed from total entitlement

getRedeemableEthFunds()

Calculate available funds for withdrawal from EVM chains.

typescript
async function getRedeemableEthFunds(
  project: Project,
  receiverAddress: string
): Promise<bigint>  // Returns wei

Collection Creation Functions

createTezosProjectVersion() (V1)

Create new collection on V1 Projects contract.

typescript
async function createTezosProjectVersion(
  params: CollectionMetadataRequest,
  collectionContractAddr: string,
  tokenContractAddr: string,
  wallet: TezosToolkit
): Promise<void>

Parameters Built:

typescript
{
  project: {
    p_project_id: string,
    p_project_name: string,
    p_creator_address: string,
    p_token_contract: string,
    p_price: number,           // mutez
    p_editions: number,
    p_mint_metadata: string,   // IPFS URL
    p_mode: MintMode,
    p_status: Status,
    p_free_minter: string,
    p_description: string,
    p_cover_uri: string,
    p_publish_date: number,    // Unix timestamp
    p_generator_entrypoint: string,
    p_width: number,
    p_height: number
  },
  p_primary_sales_split: SplitConfig,
  p_secondary_sales_split: SplitConfig,
  p_allowlist: Spot[],
  p_freelist: Spot[]
}

createTezosCollectionVersion() (V2)

Create new collection on V2 Collections contract.

typescript
async function createTezosCollectionVersion(
  params: CollectionMetadataRequest,
  collectionContractAddr: string,
  tokenContractAddr: string,
  wallet: TezosToolkit
): Promise<void>

Parameters Built:

typescript
{
  collection: {
    metadata: string,
    tokenContractAddress: string,
    freeMinter: string,
    author: string,
    mintMode: CollectionMintMode,
    status: Status,
    editions: number,
    price: number              // mutez
  },
  collectionConfig: {
    enableBatchMint: boolean,
    maxBatchMintAllowed: number,
    startDate: number,         // Unix timestamp
    endDate: number | null
  },
  freelist: Spot[],
  allowlist: Spot[],
  royalties: Receiver[],
  primarySalesReceivers: Receiver[]
}

Minting Functions

handleContractsMintBatchs()

Execute batch mint operation.

typescript
async function handleContractsMintBatchs(
  project: Project,
  mintQuantity: number,
  wallet: TezosToolkit | WalletClient,
  owner?: string  // Optional: mint to different address
): Promise<BatchOperation>

V1 Minting (Projects):

typescript
// Creates individual calls per token
for (let i = 0; i < mintQuantity; i++) {
  batch.withContractCall(
    contract.methodsObject.mint_token({
      p_id: project.id,
      universal_id: uuidv4()
    }),
    { amount: project.price, mutez: true }
  )
}

V2 Minting (Collections):

typescript
// Single call for all tokens
batch.withContractCall(
  contract.methodsObject.mint({
    quantityToMint: mintQuantity,
    collectionId: Number(project.projectId),
    owner: owner ?? userAddress
  }),
  { amount: project.price * mintQuantity, mutez: true }
)

Utility Functions

getTezCollectionKey()

Detect contract version by checking storage structure.

typescript
async function getTezCollectionKey(
  contract: ContractAbstraction<Wallet>
): Promise<TezosCollectionKey | null>

Returns:

  • "projects" - V1 contract
  • "collections" - V2 contract
  • null - Unknown/invalid contract

getQuerierClientTez()

Create read-only Tezos client.

typescript
function getQuerierClientTez(): TezosToolkit

Usage: For querying without wallet connection.

getRPCFromRegistry()

Get random RPC URL from configured registry.

typescript
function getRPCFromRegistry(chainId: ChainId): string

Purpose: Load balancing across RPC providers.


React Hooks

useCollectionContract()

Get writable contract instance.

typescript
function useCollectionContract(
  blockchain: Blockchain,
  contractAddress: string
): ContractAbstraction<Wallet> | Contract

useCollectionQuerierContract()

Get read-only contract instance.

typescript
function useCollectionQuerierContract(
  blockchain: Blockchain,
  contractAddress: string
): ContractAbstraction<ContractProvider> | Contract

useCollectionInfo()

Fetch collection metadata.

typescript
function useCollectionInfo(
  project: Project
): SWRResponse<CollectionInfo>

useCollectionConfig()

Fetch on-chain configuration.

typescript
function useCollectionConfig(
  project: Project
): SWRResponse<CollectionContractConfig>

useMintToken()

Mutation hook for minting.

typescript
function useMintToken(
  project: Project
): {
  trigger: (quantity: number) => Promise<void>,
  isMutating: boolean
}

usePublishCollection()

Mutation hook for collection creation.

typescript
function usePublishCollection(): {
  trigger: (params: CreateProjectRequest) => Promise<void>,
  isMutating: boolean
}

Error Handling

Common Contract Errors

Error CodeDescriptionResolution
NOT_ENOUGH_EDITIONSMax supply reachedCollection is sold out
NOT_ON_ALLOWLISTAddress not whitelistedCheck mint phase
COLLECTION_PAUSEDStatus is OFFWait for enablement
WRONG_AMOUNTIncorrect paymentUse exact price
MAX_BATCH_EXCEEDEDToo many tokensReduce quantity
MINT_NOT_STARTEDBefore start dateWait for start

Transaction Failures

typescript
try {
  const op = await contract.methodsObject.mint(params).send()
  await op.confirmation(3)
} catch (error) {
  if (error.message.includes('NOT_ENOUGH_EDITIONS')) {
    // Handle sold out
  }
  // ... other error handling
}

Environment Variables

bash
# Tezos Contracts
NEXT_PUBLIC_PROJECT_CONTRACT_ADDRESS=KT1...
NEXT_PUBLIC_TOKEN_CONTRACT_ADDRESS=KT1...

# Ethereum Contracts
NEXT_PUBLIC_PROJECT_CONTRACT_ADDRESS_ETH=0x...
NEXT_PUBLIC_TOKEN_CONTRACT_ADDRESS_ETH=0x...

# Base Contracts
NEXT_PUBLIC_PROJECT_CONTRACT_ADDRESS_BASE=0x...
NEXT_PUBLIC_TOKEN_CONTRACT_ADDRESS_BASE=0x...

# Network
NEXT_PUBLIC_NETWORK=mainnet
NEXT_PUBLIC_NETWORKS_REGISTRY='{...}'

FilePurpose
clients/tezos-client.tsTezos domain resolution
types/wallet.tsWallet types and chain IDs
utils/mintStatus.tsMint eligibility checking
utils/index.tsHelper functions

Released under the MIT License.