Skip to content

Commit

Permalink
Develop Market Place Contract (#1)
Browse files Browse the repository at this point in the history
* wip: getting started with MENT based on openzeppelin contracts

* wip: adding github workflow to test contracts

* wip: first run for the emt marketplace contract
  • Loading branch information
mickeymond authored Oct 30, 2023
1 parent be0a902 commit 492611c
Show file tree
Hide file tree
Showing 13 changed files with 301 additions and 1 deletion.
27 changes: 27 additions & 0 deletions .github/workflows/blockchain-ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs

name: Blockchain CI

env:
PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }}

on: [push]

jobs:
build:

runs-on: ubuntu-latest

strategy:
matrix:
node-version: [14.x, 16.x, 18.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/

steps:
- uses: actions/checkout@v3
- name: Setup and run tests using Node.js ${{ matrix.node-version }}
working-directory: ./blockchain
run: |
npm install
npm run test
3 changes: 3 additions & 0 deletions blockchain/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
PRIVATE_KEY=
MENTOR_TOKEN_DEFAULT_ADMIN=
MENTOR_TOKEN_MINTER=
14 changes: 14 additions & 0 deletions blockchain/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
node_modules
.env
coverage
coverage.json
typechain
typechain-types

# Hardhat files
cache
artifacts

# Miscellaneous
package-lock.json
yarn.lock
13 changes: 13 additions & 0 deletions blockchain/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Sample Hardhat Project

This project demonstrates a basic Hardhat use case. It comes with a sample contract, a test for that contract, and a script that deploys that contract.

Try running some of the following tasks:

```shell
npx hardhat help
npx hardhat test
REPORT_GAS=true npx hardhat test
npx hardhat node
npx hardhat run scripts/deploy.ts
```
75 changes: 75 additions & 0 deletions blockchain/contracts/EMTMarketplace.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// SPDX-License-Identifier: APACHE
pragma solidity ^0.8.20;

import "./MentorToken.sol";

contract EMTMarketplace {
// Event Definitions

event ContentUpVoted(string indexed, uint256);
event ContentDownVoted(string indexed, uint256);

// Data Definitions

address _mentToken;
mapping(string => uint256) _contentVotes;
mapping(address => mapping(string => bool)) _memberUpVotes;
mapping(address => mapping(string => bool)) _memberDownVotes;

function setMentToken(address _MENT_TOKEN_ADDRESS) public {
_mentToken = _MENT_TOKEN_ADDRESS;
}

// Function Definitions
function contentVotes(string memory _id) public view returns (uint256) {
return _contentVotes[_id];
}

function memberUpVotes(string memory _id) public view returns (bool) {
return _memberUpVotes[msg.sender][_id];
}

function memberDownVotes(string memory _id) public view returns (bool) {
return _memberDownVotes[msg.sender][_id];
}

function upVoteContent(string memory _id, address _mentor) public {
// Check if MENT Token is not address zero
require(_mentToken != address(0), "Ment Token is Address Zero!");
// Check if msg.sender has not upvoted
require(
!_memberUpVotes[msg.sender][_id],
"Member has already up voted!"
);
// Increment Content Vote
_contentVotes[_id]++;
// Update Member Votes Status
_memberUpVotes[msg.sender][_id] = true;
_memberDownVotes[msg.sender][_id] = false;
// Mint MENT Token for Content Creator (should the mentor address to passed in as an argument or stored on the blockchain?)
MentorToken(_mentToken).mint(_mentor, 1);
// Emit Event
emit ContentUpVoted(_id, _contentVotes[_id]);
}

function downVoteContent(string memory _id, address _mentor) public {
// Check if MENT Token is not address zero
require(_mentToken != address(0), "Ment Token is Address Zero!");
// Check if msg.sender has already up voted the content
require(_memberUpVotes[msg.sender][_id], "Member has not up voted!");
// Check if msg.sender has not downvoted the content
require(
!_memberDownVotes[msg.sender][_id],
"Member has already down voted!"
);
// Decrement Content Vote
_contentVotes[_id]--;
// Update Member Votes Status
_memberDownVotes[msg.sender][_id] = true;
_memberUpVotes[msg.sender][_id] = false;
// Burn MENT Token for Content Creator (should the mentor address to passed in as an argument or stored on the blockchain?)
MentorToken(_mentToken).burnFrom(_mentor, 1);
// Emit Event
emit ContentDownVoted(_id, _contentVotes[_id]);
}
}
27 changes: 27 additions & 0 deletions blockchain/contracts/MentorToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: APACHE
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";

/// @custom:security-contact [email protected]
contract MentorToken is ERC20, ERC20Burnable, AccessControl {
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");

constructor(
address defaultAdmin,
address minter
) ERC20("Mentor Token", "MENT") {
_grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);
_grantRole(MINTER_ROLE, minter);
}

function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) {
_mint(to, amount);
}

function decimals() public view virtual override returns (uint8) {
return 0;
}
}
1 change: 0 additions & 1 deletion blockchain/delete-me.md

This file was deleted.

24 changes: 24 additions & 0 deletions blockchain/hardhat.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox";
import dotenv from "dotenv";

dotenv.config();

const config: HardhatUserConfig = {
solidity: "0.8.20",
networks: {
topos: {
url: 'https://rpc.topos-subnet.testnet-1.topos.technology',
accounts: [process.env.PRIVATE_KEY as string]
},
incal: {
url: 'https://rpc.incal.testnet-1.topos.technology',
accounts: [process.env.PRIVATE_KEY as string]
}
},
gasReporter: {
enabled: true
}
};

export default config;
18 changes: 18 additions & 0 deletions blockchain/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "blockchain",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "npx hardhat test"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@nomicfoundation/hardhat-toolbox": "^3.0.0",
"@openzeppelin/contracts": "^5.0.0",
"dotenv": "^16.3.1",
"hardhat": "^2.18.3"
}
}
24 changes: 24 additions & 0 deletions blockchain/scripts/deploy-mentor-token.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { ethers } from "hardhat";
import dotenv from "dotenv";

dotenv.config();

async function main() {
const [_owner, defaultAdmin, minter] = await ethers.getSigners();

const mentorToken = await ethers.deployContract("MentorToken", [
process.env.MENTOR_TOKEN_DEFAULT_ADMIN || defaultAdmin.address,
process.env.MENTOR_TOKEN_MINTER || minter.address,
]);

await mentorToken.waitForDeployment();

console.log("Mentor Token deployed at: ", mentorToken.target);
}

// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
34 changes: 34 additions & 0 deletions blockchain/test/EMTMarketplace.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers";
import { anyValue } from "@nomicfoundation/hardhat-chai-matchers/withArgs";
import { expect } from "chai";
import { ethers } from "hardhat";

describe("EMTMarketplace", function () {
// We define a fixture to reuse the same setup in every test.
// We use loadFixture to run this setup once, snapshot that state,
// and reset Hardhat Network to that snapshot in every test.
async function deployEMTMarketplaceFixture() {
// Contracts are deployed using the first signer/account by default
const [owner, mentor, member] = await ethers.getSigners();

const EMTMarketplace = await ethers.getContractFactory("EMTMarketplace");
const emtMarketplace = await EMTMarketplace.deploy();

const MentorToken = await ethers.getContractFactory("MentorToken");
const mentorToken = await MentorToken.deploy(owner.address, emtMarketplace.target);

// Mentor Approve MarketPlace Token
await mentorToken.connect(mentor).approve(emtMarketplace.target, 1);

return { emtMarketplace, mentorToken, owner, mentor, member };
}

// Test Goes Below
describe("Deployment", function () {
it("deploys mentor token with all expected defaults", async function () {
const { emtMarketplace, mentorToken, mentor } = await loadFixture(deployEMTMarketplaceFixture);

console.log("Market Place Allowance: ", await mentorToken.allowance(mentor.address, emtMarketplace.target));
})
});
});
31 changes: 31 additions & 0 deletions blockchain/test/MentorToken.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers";
import { anyValue } from "@nomicfoundation/hardhat-chai-matchers/withArgs";
import { expect } from "chai";
import { ethers } from "hardhat";

describe("MentorToken", function () {
// We define a fixture to reuse the same setup in every test.
// We use loadFixture to run this setup once, snapshot that state,
// and reset Hardhat Network to that snapshot in every test.
async function deployMentorTokenFixture() {
// Contracts are deployed using the first signer/account by default
const [owner, minter] = await ethers.getSigners();

const MentorToken = await ethers.getContractFactory("MentorToken");
const mentorToken = await MentorToken.deploy(owner.address, minter.address);

return { mentorToken, owner, minter };
}

// Test Goes Below
describe("Deployment", function () {
it("deploys mentor token with all expected defaults", async function () {
const { mentorToken } = await loadFixture(deployMentorTokenFixture);

console.log("Total Supply: ", await mentorToken.totalSupply());
console.log("Name: ", await mentorToken.name());
console.log("Symbol: ", await mentorToken.symbol());
console.log("Decimals: ", await mentorToken.decimals());
})
});
});
11 changes: 11 additions & 0 deletions blockchain/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"compilerOptions": {
"target": "es2020",
"module": "commonjs",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"resolveJsonModule": true
}
}

0 comments on commit 492611c

Please sign in to comment.