Best practices for handling new functions when upgrading

Hello OpenZeppelin community,

I'm working on upgrading a smart contract and need advice on the best architectural approach for handling multiple minting functions.

Current situation:

  • I have an existing function called mintReservation()
  • I want to add a new function called mintWithPOI()
  • Both functions share significant common logic
  • They emit the same event: emit Minted(uint256 tokenId, address minter)

I'm considering two approaches:

1. Separate Functions with Shared Internal Logic:

function mintReservation() external {
    // Reservation-specific logic
    _commonMintLogic();
}

function mintWithPOI() external {
    // POI-specific logic
    _commonMintLogic();
}

function _commonMintLogic() internal {
    // Shared implementation
}

2. Single Generic Function with Conditional Logic:

function genericMint(MintType mintType) external {
    if (mintType == MintType.RESERVATION) {
        // Reservation-specific logic
    } else if (mintType == MintType.POI) {
        // POI-specific logic
    }
    // Common logic here
}

Additional context:

  • Future upgrades might require adding more minting methods
  • Gas efficiency and code maintainability are important considerations

Which approach would you recommend considering best practices for upgradeable contracts? Are there other patterns I should consider?

IMO, if contract bytecode size limit is not a problem for your specific case, then the prior way seems better (separate functions).

Additionally you said there will be more mint functions in the future, that will make the if else logic more complex which can lead to unnecessary confusion and vulnerabilities. You'll also need to update the Enum's elements. Seems less efficient to me.

I would also advise you to do a gas usage comparison.

1 Like