Skip to content

Commit

Permalink
✨ Allow user to mint fraktion without signature (if approved first so)
Browse files Browse the repository at this point in the history
  • Loading branch information
KONFeature committed Nov 4, 2023
1 parent fb9e798 commit 55c5222
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 3 deletions.
8 changes: 8 additions & 0 deletions contracts/minter/IMinter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,14 @@ interface IMinter {
*/
function mintFraktion(FraktionId id, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external payable;

/**
* @notice Mint a new fraktion for the given amount to the caller
* @dev Will compute the fraktion price, ensure the user have enough Frk to buy it, if try, perform the transfer
* and mint the fraktion
* @param id The id of the fraktion to be minted for the user
*/
function mintFraktion(FraktionId id) external payable;

/**
* @notice Mint a free fraktion for the given user
* @dev Will mint a new free FraktionToken for the user, by first ensuring the user doesn't have any fraktion,
Expand Down
52 changes: 49 additions & 3 deletions contracts/minter/Minter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ contract Minter is IMinter, FrakAccessControlUpgradeable, FraktionCostBadges, Mu
payable
onlyRole(FrakRoles.MINTER)
{
_mintFraktionForUser(id, to, deadline, v, r, s);
_mintFraktionForUserWithSig(id, to, deadline, v, r, s);
}

/**
Expand All @@ -277,7 +277,17 @@ contract Minter is IMinter, FrakAccessControlUpgradeable, FraktionCostBadges, Mu
* @param s Signature spec secp256k1
*/
function mintFraktion(FraktionId id, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external payable {
_mintFraktionForUser(id, msg.sender, deadline, v, r, s);
_mintFraktionForUserWithSig(id, msg.sender, deadline, v, r, s);
}

/**
* @notice Mint a new fraktion for the given amount to the caller
* @dev Will compute the fraktion price, ensure the user have enough Frk to buy it, if try, perform the transfer
* and mint the fraktion
* @param id The id of the fraktion to be minted for the user
*/
function mintFraktion(FraktionId id) external payable {
_mintFraktionForUser(id, msg.sender);
}

/**
Expand Down Expand Up @@ -339,7 +349,16 @@ contract Minter is IMinter, FrakAccessControlUpgradeable, FraktionCostBadges, Mu
* @param r Signature spec secp256k1
* @param s Signature spec secp256k1
*/
function _mintFraktionForUser(FraktionId id, address to, uint256 deadline, uint8 v, bytes32 r, bytes32 s) private {
function _mintFraktionForUserWithSig(
FraktionId id,
address to,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
)
private
{
// Get the current user balance, and exit if he already got a fraktion of this type
uint256 balance = fraktionTokens.balanceOf(to, FraktionId.unwrap(id));
if (balance != 0) {
Expand All @@ -361,6 +380,33 @@ contract Minter is IMinter, FrakAccessControlUpgradeable, FraktionCostBadges, Mu
fraktionTokens.mint(to, id, 1);
}

/**
* @notice Mint a new fraktion for the given amount and user
* @dev Will compute the fraktion price, ensure the user have enough Frk to buy it, if try, perform the transfer
* and mint the fraktion
* @param id The id of the fraktion to be minted for the user
* @param to The address on which we will mint the fraktion
*/
function _mintFraktionForUser(FraktionId id, address to) private {
// Get the current user balance, and exit if he already got a fraktion of this type
uint256 balance = fraktionTokens.balanceOf(to, FraktionId.unwrap(id));
if (balance != 0) {
revert TooManyFraktion();
}
// Get the cost of the fraktionId
uint256 cost = getCostBadge(id);
assembly {
// Emit the event
mstore(0, 1)
mstore(0x20, cost)
log3(0, 0x40, _FRACTION_MINTED_EVENT_SELECTOR, id, to)
}
// Transfer the tokens
address(frakToken).safeTransferFrom(to, foundationWallet, cost);
// Mint his fraktion
fraktionTokens.mint(to, id, 1);
}

/**
* @notice Mint a free fraktion for the given user
* @dev Will mint a new free FraktionToken for the user, by first ensuring the user doesn't have any fraktion,
Expand Down
54 changes: 54 additions & 0 deletions test/minter/Minter.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Minter } from "contracts/minter/Minter.sol";
import { IMinter } from "contracts/minter/IMinter.sol";
import { ContentId, ContentIdLib } from "contracts/libs/ContentId.sol";
import { FraktionId } from "contracts/libs/FraktionId.sol";
import { SafeTransferLib } from "solady/utils/SafeTransferLib.sol";

/// @dev Testing methods on the Minter
contract MinterTest is FrakTest {
Expand Down Expand Up @@ -216,6 +217,59 @@ contract MinterTest is FrakTest {
assertEq(fraktionTokens.balanceOf(user, FraktionId.unwrap(commonFraktionId)), 1);
}

function test_mintFraktion_noSig_ok() public withFrk(user, 100 ether) {
FraktionId commonFraktionId = contentId.commonFraktionId();
// Assert the balance is 0
assertEq(fraktionTokens.balanceOf(user, FraktionId.unwrap(commonFraktionId)), 0);

// Get the price of the fraktion
uint256 price = minter.getCostBadge(commonFraktionId);

// Approve the minter to spend the user's FRK
vm.prank(user);
frakToken.approve(address(minter), price);

// Perform the mint process
vm.prank(user);
minter.mintFraktion(commonFraktionId);

// Assert the fraktion was minted to the user
assertEq(fraktionTokens.balanceOf(user, FraktionId.unwrap(commonFraktionId)), 1);
}

function test_mintFraktion_noSig_TooManyFraktion_ko() public withFrk(user, 100 ether) {
FraktionId commonFraktionId = contentId.commonFraktionId();

// Mint first fraktion
uint256 price = minter.getCostBadge(commonFraktionId);
vm.prank(user);
frakToken.approve(address(minter), price);
vm.prank(user);
minter.mintFraktion(commonFraktionId);

// Assert the second mint will fail
vm.prank(user);
frakToken.approve(address(minter), price);
vm.expectRevert(IMinter.TooManyFraktion.selector);
vm.prank(user);
minter.mintFraktion(commonFraktionId);

// Assert the fraktion was minted to the user
assertEq(fraktionTokens.balanceOf(user, FraktionId.unwrap(commonFraktionId)), 1);
}

function test_mintFraktion_noSig_NoApproval_ko() public withFrk(user, 100 ether) {
FraktionId commonFraktionId = contentId.commonFraktionId();

// Try to mint the fraktion without any approval
vm.expectRevert(SafeTransferLib.TransferFromFailed.selector);
vm.prank(user);
minter.mintFraktion(commonFraktionId);

// Assert the fraktion wasn't minted to the user
assertEq(fraktionTokens.balanceOf(user, FraktionId.unwrap(commonFraktionId)), 0);
}

/* -------------------------------------------------------------------------- */
/* Supply functions */
/* -------------------------------------------------------------------------- */
Expand Down

0 comments on commit 55c5222

Please sign in to comment.