Skip to content

Commit

Permalink
Merge pull request #35 from yann300/add_remove_trainer
Browse files Browse the repository at this point in the history
Add/remove trainer and testing
  • Loading branch information
yann300 committed Dec 19, 2023
2 parents ad1e313 + 2b3363d commit 59514ee
Show file tree
Hide file tree
Showing 12 changed files with 9,001 additions and 8,610 deletions.
57 changes: 23 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,46 +1,35 @@
# Advanced Sample Hardhat Project
# Remix Reward

This project demonstrates an advanced Hardhat use case, integrating other tools commonly used alongside Hardhat in the ecosystem.
deployed at 0x5d470270e889b61c08C51784cDC73442c4554011 on Optimism

The project comes with a sample contract, a test for that contract, a sample script that deploys that contract, and an example of a task implementation, which simply lists the available accounts. It also comes with a variety of other tools, preconfigured to work with the project code.
## Overview

Try running some of the following tasks:
Remix reward is a program run by the Remix project.
It consists of a soulbound nft and is at the moment deployed in the Optimism chain.

```shell
npx hardhat accounts
npx hardhat compile
npx hardhat clean
npx hardhat test
npx hardhat node
npx hardhat help
REPORT_GAS=true npx hardhat test
npx hardhat coverage
npx hardhat run scripts/deploy.ts
TS_NODE_FILES=true npx ts-node scripts/deploy.ts
npx eslint '**/*.{js,ts}'
npx eslint '**/*.{js,ts}' --fix
npx prettier '**/*.{json,sol,md}' --check
npx prettier '**/*.{json,sol,md}' --write
npx solhint 'contracts/**/*.sol'
npx solhint 'contracts/**/*.sol' --fix
```
Remix Project rewards contributors, beta testers, and UX research participants with NFTs deployed on Optimism.
Remix Reward holders are able to mint a second “Remixer” user NFT badge to any wallet address of their choice.
This feature is a way to reward Remix contributors to help grow our user base into a larger and more genuine open source community of practice.

# Etherscan verification
Remix Rewards are currently not transferable. This feature leaves open the future possibility of granting holders proportional voting power to help the community decide on new features for the IDE and/or other issues governing the development of the Remix toolset.

To try out Etherscan verification, you first need to deploy a contract to an Ethereum network that's supported by Etherscan, such as Ropsten.
See the [remix reward website](https://rewards.remix.ethereum.eth.limo) for a list of already minted badges.

In this project, copy the .env.example file to a file named .env, and then edit it to fill in the details. Enter your Etherscan API key, your Ropsten node URL (eg from Alchemy), and the private key of the account which will send the deployment transaction. With a valid .env file in place, first deploy your contract:
## For Challengers

```shell
hardhat run --network ropsten scripts/sample-script.ts
```
This contract allows users to publish zero knowledge proofs generated using the Remix Challenges program.
The Remix challenges program is run regularly by the Remix project.
It consists of a list of four questions.
Participants can generate a proof that they found the answer to the four questions without publicly revealing the answers.
Publishing such a proof to the contract will mint a badge to the participant.

Then, copy the deployment address and paste it in to replace `DEPLOYED_CONTRACT_ADDRESS` in this command:
## For Trainers

```shell
npx hardhat verify --network ropsten DEPLOYED_CONTRACT_ADDRESS "Hello, Hardhat!"
```
When a trainer has been whitelisted in the contract (Please join our discord server and the community if you wish to be whitelisted as a trainer),
he/she has the ability to allow student addresses to mint a soulbound nft, within the context of a workshop, classes, etc...

# Performance optimizations
The easiest way for a trainer to allow their students to mint a badge is to run the `grantRemixerMinting.ts` from the `scripts` folder.
Then the student can either:
- run the `remixerMint.ts` script.
- or browse the [remix reward website](https://rewards.remix.ethereum.eth.limo) and go to the section `Mint a badge`

For faster runs of your tests and scripts, consider skipping ts-node's type checking by setting the environment variable `TS_NODE_TRANSPILE_ONLY` to `1` in hardhat's environment. For more details see [the documentation](https://hardhat.org/guides/typescript.html#performance-optimizations).
17 changes: 16 additions & 1 deletion contracts/RemixRewardUpgradable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,19 @@ contract Remix is Initializable, ERC721Upgradeable, ERC721EnumerableUpgradeable,
string public zkChallengePayload;
bytes public zkChallengeHash;

mapping(address => uint) public trainers;

struct TokenData {
string payload;
string tokenType;
bytes hash;
}

modifier isTrainer() {
require(trainers[msg.sender] == 1, "Caller is not a trainer");
_;
}

/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {}

Expand Down Expand Up @@ -129,7 +136,15 @@ contract Remix is Initializable, ERC721Upgradeable, ERC721EnumerableUpgradeable,
tokensData[tokenId].hash = contributorHash;
}

function grantRemixersMinting (address[] calldata remixers, uint amount) public onlyRole(DEFAULT_ADMIN_ROLE) {
function addTrainer (address trainer) public onlyRole(DEFAULT_ADMIN_ROLE) {
trainers[trainer] = 1;
}

function removeTrainer (address trainer) public onlyRole(DEFAULT_ADMIN_ROLE) {
delete trainers[trainer];
}

function grantRemixersMinting (address[] calldata remixers, uint amount) public isTrainer() {
for (uint k = 0; k < remixers.length; k++) {
allowedMinting[remixers[k]] += amount;
}
Expand Down
14 changes: 7 additions & 7 deletions contracts/artifacts/Pairing.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,24 +34,24 @@
"functionDebugData": {},
"generatedSources": [],
"linkReferences": {},
"object": "60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212203424c9cfd0d69a63ec038e806cc1f18a4c15697a0f4da59d2d79a4a1f2a494ab64736f6c63430008070033",
"opcodes": "PUSH1 0x56 PUSH1 0x37 PUSH1 0xB DUP3 DUP3 DUP3 CODECOPY DUP1 MLOAD PUSH1 0x0 BYTE PUSH1 0x73 EQ PUSH1 0x2A JUMPI PUSH4 0x4E487B71 PUSH1 0xE0 SHL PUSH1 0x0 MSTORE PUSH1 0x0 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT JUMPDEST ADDRESS PUSH1 0x0 MSTORE PUSH1 0x73 DUP2 MSTORE8 DUP3 DUP2 RETURN INVALID PUSH20 0x0 ADDRESS EQ PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x0 DUP1 REVERT INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 CALLVALUE 0x24 0xC9 0xCF 0xD0 0xD6 SWAP11 PUSH4 0xEC038E80 PUSH13 0xC1F18A4C15697A0F4DA59D2D79 LOG4 LOG1 CALLCODE LOG4 SWAP5 0xAB PUSH5 0x736F6C6343 STOP ADDMOD SMOD STOP CALLER ",
"object": "60556032600b8282823980515f1a607314602657634e487b7160e01b5f525f60045260245ffd5b305f52607381538281f3fe730000000000000000000000000000000000000000301460806040525f80fdfea2646970667358221220ce6f0606c567908e8ecea65fc676cb30d37f1318b889949696be20675d9b73b864736f6c63430008160033",
"opcodes": "PUSH1 0x55 PUSH1 0x32 PUSH1 0xB DUP3 DUP3 DUP3 CODECOPY DUP1 MLOAD PUSH0 BYTE PUSH1 0x73 EQ PUSH1 0x26 JUMPI PUSH4 0x4E487B71 PUSH1 0xE0 SHL PUSH0 MSTORE PUSH0 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH0 REVERT JUMPDEST ADDRESS PUSH0 MSTORE PUSH1 0x73 DUP2 MSTORE8 DUP3 DUP2 RETURN INVALID PUSH20 0x0 ADDRESS EQ PUSH1 0x80 PUSH1 0x40 MSTORE PUSH0 DUP1 REVERT INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 0xCE PUSH16 0x606C567908E8ECEA65FC676CB30D37F SGT XOR 0xB8 DUP10 SWAP5 SWAP7 SWAP7 0xBE KECCAK256 PUSH8 0x5D9B73B864736F6C PUSH4 0x43000816 STOP CALLER ",
"sourceMap": "1128:5104:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;1128:5104:0;;;;;;;;;;;;;;;;;"
},
"deployedBytecode": {
"functionDebugData": {},
"generatedSources": [],
"immutableReferences": {},
"linkReferences": {},
"object": "73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212203424c9cfd0d69a63ec038e806cc1f18a4c15697a0f4da59d2d79a4a1f2a494ab64736f6c63430008070033",
"opcodes": "PUSH20 0x0 ADDRESS EQ PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x0 DUP1 REVERT INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 CALLVALUE 0x24 0xC9 0xCF 0xD0 0xD6 SWAP11 PUSH4 0xEC038E80 PUSH13 0xC1F18A4C15697A0F4DA59D2D79 LOG4 LOG1 CALLCODE LOG4 SWAP5 0xAB PUSH5 0x736F6C6343 STOP ADDMOD SMOD STOP CALLER ",
"object": "730000000000000000000000000000000000000000301460806040525f80fdfea2646970667358221220ce6f0606c567908e8ecea65fc676cb30d37f1318b889949696be20675d9b73b864736f6c63430008160033",
"opcodes": "PUSH20 0x0 ADDRESS EQ PUSH1 0x80 PUSH1 0x40 MSTORE PUSH0 DUP1 REVERT INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 0xCE PUSH16 0x606C567908E8ECEA65FC676CB30D37F SGT XOR 0xB8 DUP10 SWAP5 SWAP7 SWAP7 0xBE KECCAK256 PUSH8 0x5D9B73B864736F6C PUSH4 0x43000816 STOP CALLER ",
"sourceMap": "1128:5104:0:-:0;;;;;;;;"
},
"gasEstimates": {
"creation": {
"codeDepositCost": "17200",
"executionCost": "103",
"totalCost": "17303"
"codeDepositCost": "17000",
"executionCost": "96",
"totalCost": "17096"
},
"internal": {
"P1()": "infinite",
Expand Down
4 changes: 2 additions & 2 deletions contracts/artifacts/Pairing_metadata.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"compiler": {
"version": "0.8.7+commit.e28d00a7"
"version": "0.8.22+commit.4fc1097e"
},
"language": "Solidity",
"output": {
Expand All @@ -20,7 +20,7 @@
"compilationTarget": {
"contracts/Verifier.sol": "Pairing"
},
"evmVersion": "london",
"evmVersion": "shanghai",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
Expand Down
12,507 changes: 6,387 additions & 6,120 deletions contracts/artifacts/Remix.json

Large diffs are not rendered by default.

53 changes: 49 additions & 4 deletions contracts/artifacts/Remix_metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,19 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "trainer",
"type": "address"
}
],
"name": "addTrainer",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
Expand Down Expand Up @@ -630,6 +643,19 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "trainer",
"type": "address"
}
],
"name": "removeTrainer",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
Expand Down Expand Up @@ -981,6 +1007,25 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "trainers",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
Expand Down Expand Up @@ -1270,7 +1315,7 @@
"compilationTarget": {
"contracts/RemixRewardUpgradable.sol": "Remix"
},
"evmVersion": "paris",
"evmVersion": "shanghai",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
Expand Down Expand Up @@ -1467,11 +1512,11 @@
]
},
"contracts/RemixRewardUpgradable.sol": {
"keccak256": "0x1077d41361d10c6515b225d80dd63574d80978672e8a239f8a15d5f3ed782f02",
"keccak256": "0xaa00517b578f6d22a6fa1b24e9a96f80d714d6a8f813502e516a13492a5dc499",
"license": "MIT",
"urls": [
"bzz-raw://23e852e3f96949c1d874577321ad6a92524bb3ff46f4b154ae7be348324d41ee",
"dweb:/ipfs/QmQpBbGn11mM7JbTnLDi92WaU3sQ2nqEbbPXQwN4kQRXbB"
"bzz-raw://280e95fd8055fdb78275905e6de730e4c507911eaf94bc4c00defaa741dd79ec",
"dweb:/ipfs/QmNPXJff9Jz4rUrjWcxmvmoTMuoHDGvgmYhYAsCu4Sv5N3"
]
}
},
Expand Down
4,802 changes: 2,395 additions & 2,407 deletions contracts/artifacts/Verifier.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions contracts/artifacts/Verifier_metadata.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"compiler": {
"version": "0.8.7+commit.e28d00a7"
"version": "0.8.22+commit.4fc1097e"
},
"language": "Solidity",
"output": {
Expand Down Expand Up @@ -98,7 +98,7 @@
"compilationTarget": {
"contracts/Verifier.sol": "Verifier"
},
"evmVersion": "london",
"evmVersion": "shanghai",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
Expand Down
18 changes: 9 additions & 9 deletions contracts/artifacts/ZKVerifier.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,24 +34,24 @@
"functionDebugData": {},
"generatedSources": [],
"linkReferences": {},
"object": "60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220cd9090d562633d3a6abf663b67339378a797963e23a20760a23245eb8042d9eb64736f6c63430008070033",
"opcodes": "PUSH1 0x56 PUSH1 0x37 PUSH1 0xB DUP3 DUP3 DUP3 CODECOPY DUP1 MLOAD PUSH1 0x0 BYTE PUSH1 0x73 EQ PUSH1 0x2A JUMPI PUSH4 0x4E487B71 PUSH1 0xE0 SHL PUSH1 0x0 MSTORE PUSH1 0x0 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT JUMPDEST ADDRESS PUSH1 0x0 MSTORE PUSH1 0x73 DUP2 MSTORE8 DUP3 DUP2 RETURN INVALID PUSH20 0x0 ADDRESS EQ PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x0 DUP1 REVERT INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 0xCD SWAP1 SWAP1 0xD5 PUSH3 0x633D3A PUSH11 0xBF663B67339378A797963E 0x23 LOG2 SMOD PUSH1 0xA2 ORIGIN GASLIMIT 0xEB DUP1 TIMESTAMP 0xD9 0xEB PUSH5 0x736F6C6343 STOP ADDMOD SMOD STOP CALLER ",
"sourceMap": "0:282:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;0:282:0;;;;;;;;;;;;;;;;;"
"object": "60556032600b8282823980515f1a607314602657634e487b7160e01b5f525f60045260245ffd5b305f52607381538281f3fe730000000000000000000000000000000000000000301460806040525f80fdfea264697066735822122085246efb19bf3edf97202eb9ac0f46b30f103bb23a685b5550237c9b9b03053e64736f6c63430008160033",
"opcodes": "PUSH1 0x55 PUSH1 0x32 PUSH1 0xB DUP3 DUP3 DUP3 CODECOPY DUP1 MLOAD PUSH0 BYTE PUSH1 0x73 EQ PUSH1 0x26 JUMPI PUSH4 0x4E487B71 PUSH1 0xE0 SHL PUSH0 MSTORE PUSH0 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH0 REVERT JUMPDEST ADDRESS PUSH0 MSTORE PUSH1 0x73 DUP2 MSTORE8 DUP3 DUP2 RETURN INVALID PUSH20 0x0 ADDRESS EQ PUSH1 0x80 PUSH1 0x40 MSTORE PUSH0 DUP1 REVERT INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 DUP6 0x24 PUSH15 0xFB19BF3EDF97202EB9AC0F46B30F10 EXTCODESIZE 0xB2 GASPRICE PUSH9 0x5B5550237C9B9B0305 RETURNDATACOPY PUSH5 0x736F6C6343 STOP ADDMOD AND STOP CALLER ",
"sourceMap": "57:116:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;57:116:0;;;;;;;;;;;;;;;;;"
},
"deployedBytecode": {
"functionDebugData": {},
"generatedSources": [],
"immutableReferences": {},
"linkReferences": {},
"object": "73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220cd9090d562633d3a6abf663b67339378a797963e23a20760a23245eb8042d9eb64736f6c63430008070033",
"opcodes": "PUSH20 0x0 ADDRESS EQ PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x0 DUP1 REVERT INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 0xCD SWAP1 SWAP1 0xD5 PUSH3 0x633D3A PUSH11 0xBF663B67339378A797963E 0x23 LOG2 SMOD PUSH1 0xA2 ORIGIN GASLIMIT 0xEB DUP1 TIMESTAMP 0xD9 0xEB PUSH5 0x736F6C6343 STOP ADDMOD SMOD STOP CALLER ",
"sourceMap": "0:282:0:-:0;;;;;;;;"
"object": "730000000000000000000000000000000000000000301460806040525f80fdfea264697066735822122085246efb19bf3edf97202eb9ac0f46b30f103bb23a685b5550237c9b9b03053e64736f6c63430008160033",
"opcodes": "PUSH20 0x0 ADDRESS EQ PUSH1 0x80 PUSH1 0x40 MSTORE PUSH0 DUP1 REVERT INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 DUP6 0x24 PUSH15 0xFB19BF3EDF97202EB9AC0F46B30F10 EXTCODESIZE 0xB2 GASPRICE PUSH9 0x5B5550237C9B9B0305 RETURNDATACOPY PUSH5 0x736F6C6343 STOP ADDMOD AND STOP CALLER ",
"sourceMap": "57:116:0:-:0;;;;;;;;"
},
"gasEstimates": {
"creation": {
"codeDepositCost": "17200",
"executionCost": "103",
"totalCost": "17303"
"codeDepositCost": "17000",
"executionCost": "96",
"totalCost": "17096"
}
},
"methodIdentifiers": {}
Expand Down
11 changes: 6 additions & 5 deletions contracts/artifacts/ZKVerifier_metadata.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"compiler": {
"version": "0.8.7+commit.e28d00a7"
"version": "0.8.22+commit.4fc1097e"
},
"language": "Solidity",
"output": {
Expand All @@ -20,7 +20,7 @@
"compilationTarget": {
"contracts/Proof.sol": "ZKVerifier"
},
"evmVersion": "london",
"evmVersion": "shanghai",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
Expand All @@ -33,10 +33,11 @@
},
"sources": {
"contracts/Proof.sol": {
"keccak256": "0xa43b93e3acf8404fc7031d07e28d99a50ac56543f6687afd23c4c746992177dd",
"keccak256": "0x1a0c3dc96ef35400af8997f5962a86d9a521f66d1eea044aabbb7e656f7eff7e",
"license": "MIT",
"urls": [
"bzz-raw://d49d37871b46ca5576979ed98508c339eb1db7b1e8913c9e896dd47a74771fe9",
"dweb:/ipfs/QmTkTSy6uErNc8SPR5mHzuQ7WatASVfwF4Ajr4d7xYpY28"
"bzz-raw://cb4c5696eedf87bb9e420aca2622a4bd2e6a291c9e2aafa61829feba874ad9c9",
"dweb:/ipfs/QmaLFEfzPC4SmtgcY2EVdk1NyjdhbPuWVSRevst7JForuN"
]
}
},
Expand Down
37 changes: 37 additions & 0 deletions scripts/grantRemixerMinting.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { ethers } from 'ethers'

async function main() {
try {
// proxy on Optimism.
const address = "0x5d470270e889b61c08C51784cDC73442c4554011"

// "signer" represents the current selected account and provider.
const signer = (new ethers.providers.Web3Provider(web3Provider)).getSigner()

// getContractFactory returns the compilation result.
// This will be used in the next line to instantiate an "ethers.Contract" object ot interact with the contract.
const remixV1 = await ethers.getContractFactory("Remix")

// we finally use the address, the contract artefact and the current context (provider and account)
// to instantiate an ethers.Contract object.
let contract = new ethers.Contract(address, remixV1.interface, signer);

const students = []

const txSafeMint = await contract.grantRemixersMinting(students, 1)

// this wait for the transaction to be mined.
const result = await txSafeMint.wait()

console.log(result)
} catch (e) {
console.error(e)
}
}

// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main().catch((error) => {
console.error(error)
});

Loading

0 comments on commit 59514ee

Please sign in to comment.