Skip to content

Commit

Permalink
Refactor fees
Browse files Browse the repository at this point in the history
  • Loading branch information
Vectorized committed Nov 6, 2023
1 parent 739c99d commit 2ef1644
Show file tree
Hide file tree
Showing 3 changed files with 210 additions and 174 deletions.
93 changes: 57 additions & 36 deletions contracts/modules/SuperMinterV1_1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,16 @@ contract SuperMinterV1_1 is ISuperMinterV1_1, EIP712 {
*/
mapping(address => uint256) public affiliateFeesAccrued;

/**
* @dev A mapping of `firstMinter` => `feesAccrued`.
*/
mapping(address => uint256) public firstMinterFeesAccrued;

/**
* @dev The first minter for the edition.
*/
mapping(address => address) public firstMinter;

/**
* @dev A mapping of `platform` => `price`.
*/
Expand Down Expand Up @@ -323,51 +333,54 @@ contract SuperMinterV1_1 is ISuperMinterV1_1, EIP712 {
/* ----------- AFFILIATE AND PLATFORM FEES LOGIC ------------ */

TotalPriceAndFees memory f = _totalPriceAndFees(p.tier, d, p.quantity, p.signedPrice);

uint256 remaining; // The fee sent to the Sound Edition (i.e. artist fee).
bool affiliated;
MintedLogData memory l;

unchecked {
if (msg.value != f.total) revert WrongPayment(msg.value, f.total); // Require exact payment.

remaining = f.total - (f.platformFee + f.affiliateFee); // `platformFee + affiliateFee <= total`;
l.finalArtistFee = f.total - f.platformFee; // `platformFee <= total`;
l.finalPlatformFee = f.platformFee; // Initialize to the platform fee.

if (affiliated = _isAffiliatedWithProof(d, p.affiliate, p.affiliateProof)) {
// Accrue the `affiliateBPSFee + affiliateFlatFee`.
affiliateFeesAccrued[p.affiliate] += f.affiliateFee;
// Affiliate fee workflow.
if (l.affiliated = _isAffiliatedWithProof(d, p.affiliate, p.affiliateProof)) {
l.finalArtistFee -= f.affiliateFee;
l.finalPlatformFee -= f.affiliateIncentive;
l.finalAffiliateFee = f.affiliateFee + f.affiliateIncentive;
affiliateFeesAccrued[p.affiliate] += l.finalAffiliateFee; // Accrue the affiliate fee.
} else {
// Proof may be invalid, revert to prevent unintended skipping of affiliate fee.
if (p.affiliate != address(0)) revert InvalidAffiliate();
remaining += f.affiliateBPSFee; // Redirect the `affiliateBPSFee` back to the artist.
// If not affiliated...
f.affiliateFee = 0; // Set the affiliate fee to zero, for the {Minted} event.
// Redirect the affiliate flat fee to the platform fees if not affiliated.
f.platformFee += f.affiliateFlatFee; // To be accrued.
f.platformFlatFee += f.affiliateFlatFee; // For the {Minted} event.
f.affiliateFlatFee = 0; // Set the affiliate flat fee to zero, for the {Minted} event.
}

// Accrue the platform fee, inclusive of any redirected `affiliateFlatFee`.
platformFeesAccrued[d.platform] += f.platformFee;
// Free mint fee workflow.
if (f.freeMintIncentive != 0 && f.unitPrice == 0) {
l.finalPlatformFee -= f.freeMintIncentive;
l.finalFreeMintFee = f.freeMintIncentive;
l.finalArtistFee += l.finalFreeMintFee;
}

// First minter fee workflow.
if (firstMinter[p.edition] == address(0)) firstMinter[p.edition] = p.to;
if (f.firstMinterIncentive != 0) {
l.finalPlatformFee -= f.firstMinterIncentive;
l.finalFirstMinterFee = f.firstMinterIncentive;
firstMinterFeesAccrued[firstMinter[p.edition]] += l.finalFirstMinterFee;
}

platformFeesAccrued[d.platform] += l.finalPlatformFee; // Accrue the platform fee.
}

/* ------------------------- MINT --------------------------- */

ISoundEditionV2 edition = ISoundEditionV2(p.edition);
MintedLogData memory l;
l.quantity = p.quantity;
l.fromTokenId = edition.mint{ value: remaining }(p.tier, p.to, p.quantity);
l.fromTokenId = edition.mint{ value: l.finalArtistFee }(p.tier, p.to, p.quantity);
l.allowlisted = p.allowlisted;
l.allowlistedQuantity = p.allowlistedQuantity;
l.signedClaimTicket = p.signedClaimTicket;
l.affiliate = p.affiliate;
l.affiliated = affiliated;
l.requiredEtherValue = f.total;
l.unitPrice = f.unitPrice;
l.platformFee = f.platformFee;
l.platformFlatFee = f.platformFlatFee;
l.affiliateFee = f.affiliateFee;
l.affiliateFlatFee = f.affiliateFlatFee;

emit Minted(p.edition, p.tier, p.scheduleNum, p.to, l, p.attributionId);
}
Expand Down Expand Up @@ -937,14 +950,20 @@ contract SuperMinterV1_1 is ISuperMinterV1_1, EIP712 {
* @param c The platform fee configuration.
*/
function _validatePlatformFeeConfig(PlatformFeeConfig memory c) internal pure {
if (
LibOps.or(
c.perTxFlat > MAX_PLATFORM_PER_TX_FLAT_FEE,
c.perMintFlat > MAX_PLATFORM_PER_MINT_FLAT_FEE,
c.perMintBPS > MAX_PLATFORM_PER_MINT_FEE_BPS,
c.affiliatePerMintFlat > MAX_PLATFORM_PER_MINT_FLAT_FEE
)
) revert InvalidPlatformFeeConfig();
unchecked {
uint256 incentiveSum;
incentiveSum += uint256(c.affiliateIncentive);
incentiveSum += uint256(c.freeMintIncentive);
incentiveSum += uint256(c.firstMinterIncentive);
if (
LibOps.or(
c.perTxFlat > MAX_PLATFORM_PER_TX_FLAT_FEE,
c.perMintFlat > MAX_PLATFORM_PER_MINT_FLAT_FEE,
c.perMintBPS > MAX_PLATFORM_PER_MINT_FEE_BPS,
incentiveSum > c.perTxFlat
)
) revert InvalidPlatformFeeConfig();
}
}

/**
Expand Down Expand Up @@ -1100,13 +1119,15 @@ contract SuperMinterV1_1 is ISuperMinterV1_1, EIP712 {
// The platform fee includes BPS fees deducted from sub total,
// and flat fees added to sub total.
f.platformFee = f.platformMintBPSFee + f.platformFlatFee;
// Affiliate BPS fee is to be deducted from the sub total.
// Affiliate fee is to be deducted from the sub total.
// Will be conditionally set to zero during mint if not affiliated.
f.affiliateBPSFee = LibOps.rawMulDiv(f.subTotal, d.affiliateFeeBPS, BPS_DENOMINATOR);
f.affiliateFlatFee = c.affiliatePerMintFlat * uint256(quantity);
f.affiliateFee = f.affiliateBPSFee + f.affiliateFlatFee;
f.affiliateFee = LibOps.rawMulDiv(f.subTotal, d.affiliateFeeBPS, BPS_DENOMINATOR);
// Calculate the incentives. These may be redirected away from the `platformFee`.
f.affiliateIncentive = c.affiliateIncentive * uint256(quantity);
f.freeMintIncentive = c.freeMintIncentive * uint256(quantity);
f.firstMinterIncentive = c.firstMinterIncentive * uint256(quantity);
// The total is the final value which the minter has to pay. It includes all fees.
f.total = f.subTotal + f.platformFlatFee + f.affiliateFlatFee;
f.total = f.subTotal + f.platformFlatFee;
}
}

Expand Down
47 changes: 31 additions & 16 deletions contracts/modules/interfaces/ISuperMinterV1_1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -106,16 +106,18 @@ interface ISuperMinterV1_1 is IERC165 {
// The platform per-transaction flat fees.
uint256 platformTxFlatFee;
// The total platform per-token flat fees.
// This includes all incentives.
uint256 platformMintFlatFee;
// The total platform per-token BPS fees.
uint256 platformMintBPSFee;
// The total affiliate fees.
// `affiliateBPSFee + affiliateFlatFee`.
// The affiliate fees (before any incentives).
uint256 affiliateFee;
// The total affiliate BPS fees.
uint256 affiliateBPSFee;
// The total affiliate flat fees.
uint256 affiliateFlatFee;
// The incentive for the affiliate.
uint256 affiliateIncentive;
// The incentive for free mints, to be given to the artist.
uint256 freeMintIncentive;
// The incentive for the first minter.
uint256 firstMinterIncentive;
}

/**
Expand All @@ -142,25 +144,38 @@ interface ISuperMinterV1_1 is IERC165 {
uint256 requiredEtherValue;
// The price per token.
uint256 unitPrice;
// The total platform fees.
uint256 platformFee;
// The total platform flat fees.
uint256 platformFlatFee;
// The total affiliate fees.
uint256 affiliateFee;
// The total affiliate flat fees.
uint256 affiliateFlatFee;
// The final artist fee.
uint256 finalArtistFee;
// The final platform fee.
uint256 finalPlatformFee;
// The total affiliate fee.
uint256 finalAffiliateFee;
// The final free mint fee.
uint256 finalFreeMintFee;
// The final first minter fee.
uint256 finalFirstMinterFee;
}

/**
* @dev A struct to hold the fee configuration for a platform and a tier.
*/
struct PlatformFeeConfig {
// The per-mint affiliate flat fee.
uint96 affiliatePerMintFlat;
// The amount of platform per-mint flat fee
// to give to the affiliate, if provided.
uint96 affiliateIncentive;
// The amount of platform per-mint flat fee
// to give to the artist, if the mint is free.
uint96 freeMintIncentive;
// The amount of platform per-mint flat fee
// to give to the first minter.
uint96 firstMinterIncentive;
// The per-transaction flat fee.
uint96 perTxFlat;
// The per-token flat fee.
// This fee includes:
// - `affiliateIncentive`.
// - `freeMintIncentive`.
// - `firstMinterIncentive`.
uint96 perMintFlat;
// The per-token fee BPS.
uint16 perMintBPS;
Expand Down
Loading

0 comments on commit 2ef1644

Please sign in to comment.