Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
4e773ae
BrainPass Nft Contract Added
OleanjiKingCode May 22, 2023
c4aec5a
addedexpalainable comments to functions
OleanjiKingCode May 22, 2023
c2f67f9
refined the vars in the brainpass contract
OleanjiKingCode May 22, 2023
bc3a1cc
adds brainpass deployer script
Emmanueldmlr May 22, 2023
51cd490
started testing
OleanjiKingCode May 22, 2023
1c6e3fe
updated test file and improved contract
OleanjiKingCode May 23, 2023
d88b6e8
changes noticed fix, getAllPassType Func,
OleanjiKingCode May 23, 2023
4482b93
labelling functions
OleanjiKingCode May 23, 2023
2959b63
updated contract and arranged the functions, used reverts instead of …
OleanjiKingCode May 24, 2023
a3e0bd7
changed all require func to if..revert
OleanjiKingCode May 24, 2023
9e52d56
readme doc
OleanjiKingCode May 24, 2023
ff9f7db
validate pass duration func
OleanjiKingCode May 24, 2023
347c98c
test for the new contract update
OleanjiKingCode May 24, 2023
a74cb88
Update README.md
OleanjiKingCode May 24, 2023
ae58340
test for the new contract update
OleanjiKingCode May 24, 2023
566e6a9
Merge branch 'BrainPass' of https://github.com/EveripediaNetwork/ep-c…
OleanjiKingCode May 24, 2023
ef3731a
IncresePassTime Func Refined
OleanjiKingCode May 24, 2023
5ef8ca1
changes variable names
Emmanueldmlr May 25, 2023
9a9bc99
removed for loop
OleanjiKingCode May 25, 2023
77d4183
renmoved a mapping
OleanjiKingCode May 25, 2023
0301aa2
removes unused script
Emmanueldmlr May 25, 2023
7444fee
changes function name
Emmanueldmlr May 25, 2023
3bbca93
corrected the test script
OleanjiKingCode May 25, 2023
f7c7a5d
removing unused error and added maxSupplyReached test
OleanjiKingCode May 25, 2023
888dc99
little fix in maxtokenminted per pass
OleanjiKingCode May 27, 2023
6696764
describing functions well
OleanjiKingCode May 28, 2023
b21b030
Update README.md
OleanjiKingCode May 28, 2023
639d9a0
more tests and pause Func
OleanjiKingCode May 28, 2023
8379083
Updated readme file, allows different url for differnt pass type, mor…
OleanjiKingCode May 29, 2023
92444b8
removed unsed contrac import,toggle pass type status
OleanjiKingCode May 29, 2023
d9b5bda
validating users to know if they do an activity that requires their pass
OleanjiKingCode May 29, 2023
9ed21bc
configureMintlimit test and pause contract testing
OleanjiKingCode May 30, 2023
f0dc368
seperated the withdraw func
OleanjiKingCode May 30, 2023
86eb11d
updated README.md
OleanjiKingCode May 30, 2023
cef37c7
updated readme file and contract with test
OleanjiKingCode May 31, 2023
b8fffdf
removed the id logic for passtypes
OleanjiKingCode May 31, 2023
9a230bf
added more tests for the validator
OleanjiKingCode May 31, 2023
3e6c1f6
updated the contract
OleanjiKingCode May 31, 2023
a4065fc
little changes
OleanjiKingCode Jun 1, 2023
49a3661
checking for validity of the timestamp entered
OleanjiKingCode Jun 5, 2023
2fe00bd
little fixes in the contract
OleanjiKingCode Jun 9, 2023
721b931
improved test from edited contract
OleanjiKingCode Jun 9, 2023
3f9a1eb
improved test from edited contract
OleanjiKingCode Jun 9, 2023
f717fe8
using erc721pausable
OleanjiKingCode Jun 9, 2023
717d7a0
using erc721pausable tests
OleanjiKingCode Jun 9, 2023
6260675
improving the brainPassValidator
OleanjiKingCode Jun 10, 2023
fc932ed
improved the READMe file
OleanjiKingCode Jun 11, 2023
8669373
removed unused code and improved tests
OleanjiKingCode Jun 13, 2023
fa5b0fb
removed discount
OleanjiKingCode Jun 13, 2023
b7f9781
reworked the event
OleanjiKingCode Jun 14, 2023
bb03b8e
added data to event
OleanjiKingCode Jun 14, 2023
f63d3fa
improved the contract, tests, deployment scripts
OleanjiKingCode Jun 14, 2023
7095eb3
fixed failed assertion
OleanjiKingCode Jun 14, 2023
903fdfc
deployer script
OleanjiKingCode Jun 15, 2023
b2283b2
updated the tests
OleanjiKingCode Jun 15, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,6 @@ Deploy and verify a contract
source .env

# To deploy and verify our contract
forge script script/WikiNoValidator.s.sol:WikiNoValidator --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast --verify --etherscan-api-key $ETHERSCAN_KEY -vvvv --gas-price 60 --legacy
forge script script/BrainPassDeployer.s.sol:BrainPassDeployer --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast --verify --etherscan-api-key $ETHERSCAN_KEY -vvvv --gas-price 60 --legacy

```
22 changes: 22 additions & 0 deletions script/BrainPassDeployer.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import {Script} from "../lib/forge-std/src/Script.sol";
import {console} from "../lib/forge-std/src/console.sol";

import {BrainPassCollectibles} from "../src/BrainPass/BrainPass.sol";


contract BrainPassDeployer is Script {
address constant owner = address(0xE161eB85f00eC6471E0de06bA1Cfc136C053fFfe);

function run() external {
vm.startBroadcast();

console.log("Deploying Brainpass deployer....");
BrainPassCollectibles validator = new BrainPassCollectibles(0x5E959c60f86D17fb7D764AB69B654227d464E820);
console.log("Brainpass Deployed", address(validator));

vm.stopBroadcast();
}
}
17 changes: 17 additions & 0 deletions script/BrainPassMinter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import {Script} from "../lib/forge-std/src/Script.sol";
import {console} from "../lib/forge-std/src/console.sol";
import {BrainPassCollectibles} from "../src/BrainPass/BrainPass.sol";

contract BrainPassMinter is Script {
address constant owner = address(0xaCa39B187352D9805DECEd6E73A3d72ABf86E7A0);

function run() external {
vm.startBroadcast();


vm.stopBroadcast();
}
}
2 changes: 0 additions & 2 deletions script/WikiWhitelistValidator.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,8 @@ contract WikiWhitelistValidator is Script {
validator.whitelistEditor(address(0xF6d9467758C08d05571f1bFa0a03A2286cE1F043));
validator.whitelistEditor(address(0x2fE6aCD015384E1ee5138eF79fe1a434dA8FA12e));
validator.whitelistEditor(address(0xb029c0367CCFeEFBc6D00B4cc22fcbFd6A781F5c));

validator.whitelistEditor(address(0x9fEAB70f3c4a944B97b7565BAc4991dF5B7A69ff));
validator.whitelistEditor(address(0x14B68b85E1037d1C75726b7794e99C20554f9CC3));

validator.setOwner(owner);

vm.stopBroadcast();
Expand Down
284 changes: 284 additions & 0 deletions src/BrainPass/BrainPass.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,284 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import "openzeppelin-contracts/contracts/token/ERC721/ERC721.sol";
import {Counters} from "openzeppelin-contracts/contracts/utils/Counters.sol";
import {Owned} from "solmate/auth/Owned.sol";
import {SafeMath} from "openzeppelin-contracts/contracts/utils/math/SafeMath.sol";

interface IERC20 {
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);

function transfer(address to, uint256 amount) external returns (bool);

function balanceOf(address account) external view returns (uint256);
}

/// @title BRAIN Pass NFT
/// @author Oleanji
/// @notice A pass for IQ Wiki Editors

contract BrainPassCollectibles is ERC721, Owned {
Copy link
Copy Markdown
Member

@kesar kesar May 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some improvements I've been thinking after seeing the codebase:

  • We might want to have some kind of configuration that allow us to change stuff like: min. max minting max time
  • We might want to use seconds across the calculations of minting / pricing. That will simplify a lot the code and avoid doing many multiplications
  • A better improved nft types management system ( delete / pause / etc)

Besides that, there is a missing contract needed that connects the owning of these NFTs with IQ wiki possibility to push wikis

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean the Wiki contract part of the ep contracts?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the validator / whitelist contracts

/// -----------------------------------------------------------------------
/// Errors
/// -----------------------------------------------------------------------

error MintingPaymentFailed();
error IncreseTimePaymentFailed();
error UserBalanceNotEnough();

/// -----------------------------------------------------------------------
/// Inheritances
/// -----------------------------------------------------------------------
using SafeMath for uint256;
Comment thread
OleanjiKingCode marked this conversation as resolved.
Outdated
using Counters for Counters.Counter;

/// -----------------------------------------------------------------------
/// Structs
/// -----------------------------------------------------------------------
struct UserPassItem {
uint256 tokenId;
uint256 passId;
uint256 startTimestamp;
uint256 endTimestamp;
}

struct PassType {
uint256 passId;
string name;
uint256 pricePerDay;
string tokenURI;
uint256 maxTokens;
uint256 discount;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whats maxTokens & discount?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think maxTokens should be the max no of NFTS that can be minted (in the case of a limited supply). and for the discount, we felt we might want to give a bit of discount to those subscribing for a long time at once(say a yr subscriptions).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you mention here that the discount param is "to those subscribing for a long time at once". Code doesnt do that at all. it just apply a generic discount to price. which its the same to not having that param and reduce the price per day.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this has never been addressed. Please review my comments before asking for a new code review

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

third time: please remove discount. it doesnt make any sense current implementation.

if you do a 10% discount its the same that if you just reduce price by 10%.

uint256 lastTokenIdMinted;
}

/// -----------------------------------------------------------------------
/// Mappings
/// -----------------------------------------------------------------------
mapping(uint256 => PassType) public passTypes;
mapping(address => mapping(uint256 => UserPassItem))
public addressToNFTPass;
mapping(address => mapping(uint256 => bool)) public addressToPassId;

/// -----------------------------------------------------------------------
/// Constant
/// -----------------------------------------------------------------------
address public IqToken;

/// -----------------------------------------------------------------------
/// Variables
/// -----------------------------------------------------------------------
string public baseTokenURI;
Comment thread
kesar marked this conversation as resolved.
Counters.Counter private tokenIds;

/// -----------------------------------------------------------------------
/// Constructor
/// -----------------------------------------------------------------------
constructor(
address IqAddr
) ERC721("BRAINY EDITOR PASS", "BEP") Owned(msg.sender) {
Comment thread
kesar marked this conversation as resolved.
Outdated
IqToken =IqAddr;
}

function baseURI() internal view virtual returns (string memory) {
return baseTokenURI;
}

function setBaseURI(string memory tokenURI) internal {
baseTokenURI = tokenURI;
}

/// @notice Add a new Pass Type
/// @param passId and others are the details needed for a passType
function addPassType(
uint256 passId,
uint256 pricePerDay,
string memory tokenURI,
string memory name,
uint256 maxTokens,
uint256 discount
) public onlyOwner {
require(bytes(tokenURI).length > 0, "Invalid token URI");
require(maxTokens > 0, "Invalid max tokens");

passTypes[passId] = PassType(
passId,
name,
pricePerDay,
tokenURI,
maxTokens,
discount,
0
);

emit NewPassAdded(passId, name, maxTokens, pricePerDay);
}

/// @notice Mint and NFT of a particular passtype
/// @param passId The id of the passtype to mint
function mintNFT(
uint256 passId,
uint256 startTimestamp,
uint256 endTimestamp
) public {
require(
addressToPassId[msg.sender][passId] != true,
"Max NFTs per address reached"
);

PassType storage passType = passTypes[passId];

require(passType.maxTokens != 0, "Pass type not found");

require(
passType.lastTokenIdMinted.add(1) <= passType.maxTokens,
"Max supply reached"
);

uint256 price = calculatePrice(passId, startTimestamp, endTimestamp);

if (IERC20(IqToken).balanceOf(msg.sender) < price)
revert UserBalanceNotEnough();
Comment thread
kesar marked this conversation as resolved.
Outdated

bool success = IERC20(IqToken).transferFrom(msg.sender, owner, 1e18);
Comment thread
kesar marked this conversation as resolved.
Outdated
if (!success) revert MintingPaymentFailed();

uint256 tokenId = passType.lastTokenIdMinted + 1;
setBaseURI(passType.tokenURI);
Comment thread
kesar marked this conversation as resolved.
Outdated
_safeMint(msg.sender, tokenId);
Comment thread
kesar marked this conversation as resolved.
Outdated

addressToPassId[msg.sender][passId] = true;

UserPassItem memory purchase = UserPassItem(
tokenId,
passId,
startTimestamp,
endTimestamp
);
addressToNFTPass[msg.sender][tokenId] = purchase;
passType.lastTokenIdMinted = tokenId;

emit BrainPassBought(
msg.sender,
tokenId,
passId,
startTimestamp,
endTimestamp
);
}

/// @notice Calculate the price of an Nft
/// @param startTimestamp and endTimestamp are used to calc the price to be paid
function calculatePrice(
uint256 passId,
uint256 startTimestamp,
uint256 endTimestamp
) public view returns (uint256) {
PassType memory passType = passTypes[passId];
//duration in days
uint256 duration = endTimestamp.sub(startTimestamp);
uint256 totalPrice = duration.mul(passType.pricePerDay);
Comment thread
kesar marked this conversation as resolved.
Outdated
if (passType.discount > 0) {
uint256 discountAmount = totalPrice.mul(passType.discount).div(100);
totalPrice = totalPrice.sub(discountAmount);
}

return totalPrice;
}

/// @notice Increase the time to hold a PassNft
/// @param tokenId The Id of the NFT whose time is to be increased
function increasePassTime(
uint256 tokenId,
uint256 passIdNum,
uint newStartTime,
uint256 newEndTime
) public {
require(
msg.sender == ownerOf(tokenId),
"You cannot increase the time for an NFT you don't own"
);

UserPassItem storage pass = addressToNFTPass[ownerOf(tokenId)][tokenId];
uint256 price = calculatePrice(passIdNum, newStartTime, newEndTime);
Comment thread
kesar marked this conversation as resolved.
Outdated
bool success = IERC20(IqToken).transferFrom(msg.sender, owner, price);
if (!success) revert IncreseTimePaymentFailed();

pass.startTimestamp = newStartTime;
pass.endTimestamp = newEndTime;

emit TimeIncreased(
msg.sender,
tokenId,
pass.startTimestamp,
pass.endTimestamp
);
}

/// @notice Gets all the NFT owned by an address
/// @param user The address of the user
function getUserNFTs(
address user,
uint passIdNum
) public view returns (UserPassItem[] memory) {
uint256 userTokenCount = balanceOf(user);
PassType memory passType = passTypes[passIdNum];
UserPassItem[] memory userTokens = new UserPassItem[](userTokenCount);
uint256 counter = 0;
for (uint256 i = 0; i < passType.maxTokens; i++) {
if (ownerOf(i) == user) {
userTokens[counter] = addressToNFTPass[msg.sender][i];
counter++;
}
}
return userTokens;
}

/// @notice Gets all the details of a passtype
/// @param passId The id of the passtype
function getAllPassType(
uint256 passId
) public view returns (PassType memory) {
PassType memory passType = passTypes[passId];
return (passType);
}

/// @notice Withdraws any amount in the contract
function withdraw() public payable onlyOwner {
uint256 balance = address(this).balance;
require(balance > 0, "No ether left to withdraw");
(bool success, ) = (msg.sender).call{value: balance}("");
require(success, "Transfer failed.");
}

/// -----------------------------------------------------------------------
/// Events
/// -----------------------------------------------------------------------

event BrainPassBought(
address indexed _owner,
uint256 _passId,
uint256 _tokenId,
uint256 _startTimestamp,
uint256 _endTimestamp
);

event TimeIncreased(
address indexed _owner,
uint256 _tokenId,
uint256 _startTimestamp,
uint256 _newEndTimestamp
);

event NewPassAdded(
uint256 indexed _passId,
string _name,
uint256 _maxtokens,
uint256 _pricePerDay
);
}
Loading