Skip to content

Commit

Permalink
T
Browse files Browse the repository at this point in the history
  • Loading branch information
Vectorized committed Mar 20, 2024
1 parent c86731e commit 2d345b6
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 20 deletions.
4 changes: 0 additions & 4 deletions .husky/pre-push

This file was deleted.

74 changes: 62 additions & 12 deletions contracts/modules/SuperMinterE.sol
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ contract SuperMinterE is ISuperMinterE, EIP712 {
/**
* @dev A mapping of `platform` => `token` => `feesAccrued`.
*/
mapping(address => address(address => uint256)) public platformERC20FeesAccrued;
mapping(address => mapping(address => uint256)) public platformERC20FeesAccrued;

/**
* @dev A mapping of `platform` => `feeRecipient`.
Expand All @@ -215,7 +215,7 @@ contract SuperMinterE is ISuperMinterE, EIP712 {
/**
* @dev A mapping of `affiliate` => `token` => `feesAccrued`.
*/
mapping(address => address(address => uint256)) public affiliateERC20FeesAccrued;
mapping(address => mapping(address => uint256)) public affiliateERC20FeesAccrued;

/**
* @dev A mapping of `platform` => `price`.
Expand Down Expand Up @@ -318,12 +318,15 @@ contract SuperMinterE is ISuperMinterE, EIP712 {
d.mode = c.mode;
d.flags = _MINT_CREATED_FLAG;
d.next = editionHead.head;
d.erc20 = c.erc20;
editionHead.head = uint16((uint256(c.tier) << 8) | uint256(scheduleNum));

// Skip writing zeros, to avoid cold SSTOREs.
if (c.affiliateMerkleRoot != bytes32(0)) d.affiliateMerkleRoot = c.affiliateMerkleRoot;
if (c.merkleRoot != bytes32(0)) d.merkleRoot = c.merkleRoot;

if (c.erc20 != address(0) && c.erc20.code.length == 0) revert ERC20DoesNotExist();

emit MintCreated(c.edition, c.tier, scheduleNum, c);
}
}
Expand All @@ -339,12 +342,13 @@ contract SuperMinterE is ISuperMinterE, EIP712 {
_requireMintOpen(d);

// Perform the sub workflows depending on the mint mode.
uint8 mode = d.mode;
if (mode == VERIFY_MERKLE) _verifyMerkle(d, p);
else if (mode == VERIFY_SIGNATURE) _verifyAndClaimSignature(d, p);
else if (mode == PLATFORM_AIRDROP) revert InvalidMode();

_incrementMinted(mode, d, p);
{
uint8 mode = d.mode;
if (mode == VERIFY_MERKLE) _verifyMerkle(d, p);
else if (mode == VERIFY_SIGNATURE) _verifyAndClaimSignature(d, p);
else if (mode == PLATFORM_AIRDROP) revert InvalidMode();
_incrementMinted(mode, d, p);
}

/* ----------------- COMPUTE AND ACCRUE FEES ---------------- */

Expand All @@ -356,7 +360,10 @@ contract SuperMinterE is ISuperMinterE, EIP712 {

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

if (msg.value != f.total) revert WrongPayment(msg.value, f.total); // Require exact payment.
l.erc20 = d.erc20;
if (l.erc20 == address(0)) {
if (msg.value != f.total) revert WrongPayment(msg.value, f.total); // Require exact payment.
}

l.finalArtistFee = f.finalArtistFee;
l.finalPlatformFee = f.finalPlatformFee;
Expand All @@ -367,24 +374,41 @@ contract SuperMinterE is ISuperMinterE, EIP712 {
// Overflow not possible since all fees are uint96s.
unchecked {
if (l.finalAffiliateFee != 0) {
affiliateFeesAccrued[p.affiliate] += l.finalAffiliateFee;
if (l.erc20 == address(0)) {
affiliateFeesAccrued[p.affiliate] += l.finalAffiliateFee;
} else {
affiliateERC20FeesAccrued[p.affiliate][l.erc20] += l.finalAffiliateFee;
}
}
if (l.finalPlatformFee != 0) {
platformFeesAccrued[d.platform] += l.finalPlatformFee;
if (l.erc20 == address(0)) {
platformFeesAccrued[d.platform] += l.finalPlatformFee;
} else {
platformERC20FeesAccrued[d.platform][l.erc20] += l.finalPlatformFee;
}
}
}

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

ISoundEditionV2_1 edition = ISoundEditionV2_1(p.edition);
l.quantity = 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.requiredEtherValue = f.total;
l.unitPrice = f.unitPrice;

if (l.erc20 == address(0)) {
l.fromTokenId = edition.mint{ value: l.finalArtistFee }(p.tier, p.to, p.quantity);
} else {
l.fromTokenId = edition.mint(p.tier, p.to, p.quantity);
SafeTransferLib.safeTransferFrom(l.erc20, msg.sender, address(edition), l.finalArtistFee);
unchecked {
uint256 feesToThis = l.finalPlatformFee + l.finalAffiliateFee;
SafeTransferLib.safeTransferFrom(l.erc20, msg.sender, address(this), feesToThis);
}
}
emit Minted(p.edition, p.tier, p.scheduleNum, p.to, l, p.attributionId);

return l.fromTokenId;
Expand Down Expand Up @@ -588,6 +612,18 @@ contract SuperMinterE is ISuperMinterE, EIP712 {
}
}

/**
* @inheritdoc ISuperMinterE
*/
function withdrawERC20ForAffiliate(address erc20, address affiliate) public {
uint256 accrued = affiliateERC20FeesAccrued[affiliate][erc20];
if (accrued != 0) {
affiliateERC20FeesAccrued[affiliate][erc20] = 0;
SafeTransferLib.safeTransfer(erc20, affiliate, accrued);
emit AffiliateERC20FeesWithdrawn(affiliate, erc20, accrued);
}
}

/**
* @inheritdoc ISuperMinterE
*/
Expand All @@ -602,6 +638,20 @@ contract SuperMinterE is ISuperMinterE, EIP712 {
}
}

/**
* @inheritdoc ISuperMinterE
*/
function withdrawERC20ForPlatform(address erc20, address platform) public {
address recipient = platformFeeAddress[platform];
_validatePlatformFeeAddress(recipient);
uint256 accrued = platformERC20FeesAccrued[platform][erc20];
if (accrued != 0) {
platformERC20FeesAccrued[platform][erc20] = 0;
SafeTransferLib.safeTransfer(erc20, recipient, accrued);
emit PlatformERC20FeesWithdrawn(platform, erc20, accrued);
}
}

// Platform fee functions:
// -----------------------
// These functions enable any caller to set their own platform fees.
Expand Down
45 changes: 41 additions & 4 deletions contracts/modules/interfaces/ISuperMinterE.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ pragma solidity ^0.8.16;
import { IERC165 } from "openzeppelin/utils/introspection/IERC165.sol";

/**
* @title ISuperMinterV2
* @title ISuperMinterE
* @notice The interface for the generalized minter.
*/
interface ISuperMinterV2 is IERC165 {
interface ISuperMinterE is IERC165 {
// =============================================================
// STRUCTS
// =============================================================
Expand Down Expand Up @@ -158,6 +158,8 @@ interface ISuperMinterV2 is IERC165 {
// The final platform fee
// (inclusive of `finalPlatformReward`, `perTxFlat`, sum of `perMintBPS`).
uint256 finalPlatformFee;
// The erc20 token for payment, if any.
address erc20;
}

/**
Expand Down Expand Up @@ -373,13 +375,29 @@ interface ISuperMinterV2 is IERC165 {
*/
event AffiliateFeesWithdrawn(address indexed affiliate, uint256 accrued);

/**
* @dev Emitted when affiliate ERC20 fees are withdrawn.
* @param affiliate The recipient of the fees.
* @param erc20 The erc20 token address.
* @param accrued The amount of Ether accrued and withdrawn.
*/
event AffiliateERC20FeesWithdrawn(address indexed affiliate, address indexed erc20, uint256 accrued);

/**
* @dev Emitted when platform fees are withdrawn.
* @param platform The platform address.
* @param accrued The amount of Ether accrued and withdrawn.
*/
event PlatformFeesWithdrawn(address indexed platform, uint256 accrued);

/**
* @dev Emitted when platform ERC20 fees are withdrawn.
* @param platform The platform address.
* @param erc20 The erc20 token address.
* @param accrued The amount of Ether accrued and withdrawn.
*/
event PlatformERC20FeesWithdrawn(address indexed platform, address indexed erc20, uint256 accrued);

/**
* @dev Emitted when the platform fee recipient address is updated.
* @param platform The platform address.
Expand Down Expand Up @@ -545,6 +563,11 @@ interface ISuperMinterV2 is IERC165 {
*/
error NotConfigurable();

/**
* @dev The ERC20 contract does not exist.
*/
error ERC20DoesNotExist();

// =============================================================
// PUBLIC / EXTERNAL WRITE FUNCTIONS
// =============================================================
Expand Down Expand Up @@ -699,17 +722,31 @@ interface ISuperMinterV2 is IERC165 {
) external;

/**
* @dev Withdraws all accrued fees of the affiliate, to the affiliate.
* @dev Withdraws all accrued ETH fees of the affiliate, to the affiliate.
* @param affiliate The affiliate address.
*/
function withdrawForAffiliate(address affiliate) external;

/**
* @dev Withdraws all accrued fees of the platform, to the their fee address.
* @dev Withdraws all accrued ETH fees of the platform, to the their fee address.
* @param platform The platform address.
*/
function withdrawForPlatform(address platform) external;

/**
* @dev Withdraws all accrued ERC20 fees of the affiliate, to the affiliate.
* @param erc20 The erc20 token address.
* @param affiliate The affiliate address.
*/
function withdrawERC20ForAffiliate(address erc20, address affiliate) external;

/**
* @dev Withdraws all accrued ERC20 fees of the platform, to the their fee address.
* @param erc20 The erc20 token address.
* @param platform The platform address.
*/
function withdrawERC20ForPlatform(address erc20, address platform) external;

/**
* @dev Allows the caller, as a platform, to set their fee address
* @param recipient The platform fee address of the caller.
Expand Down

0 comments on commit 2d345b6

Please sign in to comment.