Skip to content

Commit

Permalink
redeploy with Oracle and WorldIdRegister separated
Browse files Browse the repository at this point in the history
  • Loading branch information
lorbke committed Nov 16, 2024
1 parent 8786e84 commit 7a78cb5
Show file tree
Hide file tree
Showing 10 changed files with 434 additions and 484 deletions.
58 changes: 58 additions & 0 deletions packages/foundry/broadcast/Deploy.s.sol/480/run-1731797301.json

Large diffs are not rendered by default.

45 changes: 21 additions & 24 deletions packages/foundry/broadcast/Deploy.s.sol/480/run-latest.json

Large diffs are not rendered by default.

312 changes: 312 additions & 0 deletions packages/foundry/contracts/HumanOracleWithWorldIdRegister.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,312 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {IWorldID} from "../lib/world-id-onchain-template/contracts/src/interfaces/IWorldID.sol";
import {WorldIdRegister} from "./WorldIdRegister.sol";
import {ByteHasher} from "./ByteHasher.sol";
// import "forge-std/console.sol";

contract HumanOracleWithWorldIdRegister is WorldIdRegister {

// ====================
// ====== Structs =====
// ====================

struct Option {
uint256 totalStake;
mapping (address => uint256) userStakes;
}

struct Stake {
Option[] answers;
uint256 totalStake;
mapping (address => bool) hasUserClaimed;
}

struct Vote {
uint256 id;
string question;
string[] answers;
uint256 startBlock;
uint256 durationInBlocks;
}

// ====================
// ==== Variables =====
// ====================

// public
mapping (uint256 => Stake) public stakesForVoteIds;
Vote[] votes;

// private
mapping (uint256 => bool) private registeredNullifierHashes;


// ====================
// ====== Events ======
// ====================

event VoteCreated(uint256 indexed voteId, string question, uint256 startBlock, uint256 durationInBlocks);

event VoteSubmitted(address indexed user, uint256 indexed voteId, uint256 answerIndex, uint256 stakeAmount);

event RewardClaimed(address indexed user, uint256 indexed voteId, uint256 rewardAmount);

// ====================
// ==== Modifiers =====
// ====================

modifier hasNotVoted(uint256 voteId) {
uint256 answerCount = getStakeAnswerCount(voteId);
address userAddr = address(msg.sender);
for (uint i = 0; i < answerCount; i++) {
bool hasVoted = hasUserVotedForStakeAnswer(userAddr, voteId, i);
if (hasVoted == true) {
revert("user already voted");
}
}
_;
}

modifier voteActive(uint256 voteId) {
require(getVoteStartBlock(voteId) <= block.number, "vote has not started");
require(getVoteStartBlock(voteId) + getVoteDurationInBlocks(voteId) >= block.number, "vote has ended");
_;
}

modifier voteEnded(uint256 voteId) {
require(getVoteStartBlock(voteId) + getVoteDurationInBlocks(voteId) < block.number, "vote still active");
_;
}

modifier userExists() {
if (users[address(msg.sender)].nullifierHash == 0) {
revert("user not existing");
}
_;
}

// security measurement
// modifier userOldEnough(uint256 voteId) {
// if (users[address(msg.sender)].createdAtBlock > getVoteStartBlock(voteId)) {
// revert("user was created after voting begun");
// }
// _;
// }

// ====================
// === Constructor ====
// ====================

constructor(address _worldIdAddr, uint256 _groupId, string memory _appId, string memory _action) WorldIdRegister(_worldIdAddr, _groupId, _appId, _action) {
}

// ====================
// ==== Functions =====
// ====================

// external

function submitVotingDecisionWithStake(uint256 voteId, uint256 answerIndex, uint256 amount) userExists() hasNotVoted(voteId) voteActive(voteId) external {
require(amount <= 5, "max staking amount is 5");
address userAddr = address(msg.sender);
stakeForAnswer(userAddr, voteId, answerIndex, amount);
emit VoteSubmitted(userAddr, voteId, answerIndex, amount);
}

function claimRewardForVote(uint256 voteId) voteEnded(voteId) external returns (uint256) {
address userAddr = address(msg.sender);
require(!hasUserClaimedForVote(userAddr, voteId), "user already claimed");
setUserHasClaimedToTrueForVote(userAddr, voteId);
uint256 payout = getStakeResolvedUserAmount(userAddr, voteId);
emit RewardClaimed(userAddr, voteId, payout);
return payout;
}

function isUserRegistered(address userAddr) external view returns (bool) {
if (users[userAddr].nullifierHash != 0) {
return true;
} else {
return false;
}
}

function createVote(string calldata question, string[] calldata answers, uint256 startBlock, uint256 durationInBlocks, uint256 bounty) external {
uint256 voteId = votes.length;
Vote memory newVote = Vote({
id: voteId,
question: question,
answers: answers,
startBlock: startBlock,
durationInBlocks: durationInBlocks
});
votes.push(newVote);

createNewStake(voteId, bounty);

emit VoteCreated(voteId, getVoteQuestion(voteId), getVoteStartBlock(voteId), getVoteDurationInBlocks(voteId));
}

function getVotingPage(uint256 voteId) external view returns (
string memory question,
string[] memory answers,
uint256 totalStake,
uint256[] memory stakePerAnswer
) {
uint256 answerCount = getStakeAnswerCount(voteId);
totalStake = getStakeTotalStake(voteId);
stakePerAnswer = new uint256[](answerCount);

for (uint i = 0; i < answerCount; i++) {
stakePerAnswer[i] = getStakeAnswerStake(voteId, i);
}

return (getVoteQuestion(voteId), getVoteAnswers(voteId), totalStake, stakePerAnswer);
}

function getVotingList() external view returns (
uint256[] memory ids,
string[] memory questions,
uint256[] memory totalStakes
) {
uint256 voteCount = getVoteCount();
ids = new uint256[](voteCount);
questions = new string[](voteCount);
totalStakes = new uint256[](voteCount);

for (uint i = 0; i < voteCount; i++) {
ids[i] = i;
questions[i] = getVoteQuestion(i);
totalStakes[i] = getStakeTotalStake(i);
}

return (ids, questions, totalStakes);
}

function isVotingOver(uint256 voteId) external view returns (bool) {
if (block.number > getVoteEndBlock(voteId)) {
return true;
} else {
return false;
}
}

function hasUserVotedForVote(address userAddr, uint256 voteId) external view returns (bool) {
uint256 answerCount = getStakeAnswerCount(voteId);
for (uint i = 0; i < answerCount; i++) {
if (hasUserVotedForStakeAnswer(userAddr, voteId, i)) {
return true;
}
}
return false;
}

function hasUserClaimedForVote(address userAddr, uint256 voteId) public view returns (bool) {
return stakesForVoteIds[voteId].hasUserClaimed[userAddr];
}

function getUserPayoutForVote(address userAddr, uint256 voteId) public view returns (uint256 payout) {
return getStakeResolvedUserAmount(userAddr, voteId);
}

// internal

// stake related
function createNewStake(uint256 voteId, uint256 initialStake) internal {
Stake storage newStake = stakesForVoteIds[voteId];
newStake.totalStake = initialStake;
uint256 answerCount = votes[voteId].answers.length;
uint256 initialStakePerAnswer = initialStake / answerCount;
for (uint i = 0; i < answerCount; i++) {
newStake.answers.push();
newStake.answers[i].totalStake = initialStakePerAnswer;
}
}

function stakeForAnswer(address userAddr, uint256 voteId, uint256 answerIndex, uint256 amount) internal {
stakesForVoteIds[voteId].answers[answerIndex].userStakes[userAddr] = amount;
stakesForVoteIds[voteId].answers[answerIndex].totalStake += amount;
stakesForVoteIds[voteId].totalStake += amount;
}

function setUserHasClaimedToTrueForVote(address userAddr, uint256 voteId) internal {
stakesForVoteIds[voteId].hasUserClaimed[userAddr] = true;
}

function getStakeResolvedUserAmount(address userAddr, uint256 voteId) internal view returns (uint256 amount) {
uint256 highestStakeAnswerIndex = getStakeHighestAnswerIndex(voteId);
if (!hasUserVotedForStakeAnswer(userAddr, voteId, highestStakeAnswerIndex)) {
return 0;
}
uint256 userStake = getUserStakeOfStakeAnswer(userAddr, voteId, highestStakeAnswerIndex);
uint256 totalStake = getStakeTotalStake(voteId);
uint256 answerStake = getStakeAnswerStake(voteId, highestStakeAnswerIndex);
uint256 userPayout = totalStake / answerStake * userStake;
return userPayout;
}

function getStakeHighestAnswerIndex(uint256 voteId) internal view returns (uint256 answerIndex) {
uint256 answerCount = getStakeAnswerCount(voteId);
uint256 highestAmount = 0;
uint256 highestIndex = 0;

for (uint i = 0; i < answerCount; i++) {
uint256 answerStake = getStakeAnswerStake(voteId, i);
if (highestAmount < answerStake) {
highestAmount = answerStake;
highestIndex = i;
}
}
return highestIndex;
}

function getStakeAnswerStake(uint256 voteId, uint256 answerIndex) internal view returns (uint256 stake) {
return stakesForVoteIds[voteId].answers[answerIndex].totalStake;
}

function getStakeAnswerCount(uint256 voteId) internal view returns (uint256 count) {
return stakesForVoteIds[voteId].answers.length;
}

function getStakeTotalStake(uint256 voteId) internal view returns (uint256 stake) {
return stakesForVoteIds[voteId].totalStake;
}

function hasUserVotedForStakeAnswer(address userAddr, uint256 voteId, uint256 answerIndex) internal view returns (bool voted) {
if (stakesForVoteIds[voteId].answers[answerIndex].userStakes[userAddr] != 0) {
return true;
} else {
return false;
}
}

function getUserStakeOfStakeAnswer(address userAddr, uint256 voteId, uint256 answerIndex) internal view returns (uint256 amount) {
return stakesForVoteIds[voteId].answers[answerIndex].userStakes[userAddr];
}

// vote related
function getVoteCount() internal view returns (uint256 count) {
return votes.length;
}

function getVoteQuestion(uint256 voteId) internal view returns (string memory question) {
return votes[voteId].question;
}

function getVoteAnswers(uint256 voteId) internal view returns (string[] memory answers) {
return votes[voteId].answers;
}

function getVoteStartBlock(uint256 voteId) internal view returns (uint256 startBlock) {
return votes[voteId].startBlock;
}

function getVoteDurationInBlocks(uint256 voteId) internal view returns (uint256 durationInBlocks) {
return votes[voteId].durationInBlocks;
}

function getVoteEndBlock(uint256 voteId) internal view returns (uint256 endBlock) {
return getVoteStartBlock(voteId) + getVoteDurationInBlocks(voteId);
}
}
2 changes: 1 addition & 1 deletion packages/foundry/contracts/WorldIDRegister.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {IWorldID} from "../lib/world-id-onchain-template/contracts/src/interface
import {ByteHasher} from "./ByteHasher.sol";
// import "forge-std/console.sol";

contract WorldIDRegister {
contract WorldIdRegister {

using ByteHasher for bytes;

Expand Down
3 changes: 2 additions & 1 deletion packages/foundry/contractsToVerify/HumanOracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ pragma solidity ^0.8.28;

import {IWorldID} from "./IWorldID.sol";
import {ByteHasher} from "./ByteHasher.sol";
import {WorldIDregister} from "."
// import "forge-std/console.sol";

contract HumanOracle {
contract HumanOracle is {

using ByteHasher for bytes;

Expand Down
8 changes: 6 additions & 2 deletions packages/foundry/script/Deploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { DeployMockHumanOracle } from "./DeployMockHumanOracle.s.sol";
import { DeployHumanOracle } from "./DeployHumanOracle.s.sol";
import { DeployHumanOracleWithVault } from "./DeployHumanOracleWithVault.s.sol";
import { DeployWorldIDRegister } from "./DeployWorldIDRegister.s.sol";
import { DeployHumanOracleWithWorldIdRegister } from "./DeployHumanOracleWithWorldIdRegister.s.sol";

contract DeployScript is ScaffoldETHDeploy {
function run() external {
Expand All @@ -15,8 +16,11 @@ contract DeployScript is ScaffoldETHDeploy {
// DeployHumanOracle deployHumanOracle = new DeployHumanOracle();
// deployHumanOracle.run();

DeployHumanOracleWithVault deployHumanOracleWithVault = new DeployHumanOracleWithVault();
deployHumanOracleWithVault.run();
// DeployHumanOracleWithVault deployHumanOracleWithVault = new DeployHumanOracleWithVault();
// deployHumanOracleWithVault.run();

DeployHumanOracleWithWorldIdRegister deployHumanOracleWithWorldIdRegister = new DeployHumanOracleWithWorldIdRegister();
deployHumanOracleWithWorldIdRegister.run();

// DeployWorldIDRegister worldIDregister = new DeployWorldIDRegister();
// worldIDregister.run();
Expand Down
22 changes: 22 additions & 0 deletions packages/foundry/script/DeployHumanOracleWithWorldIdRegister.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "../contracts/HumanOracleWithWorldIdRegister.sol";
import "./DeployHelpers.s.sol";

contract DeployHumanOracleWithWorldIdRegister is ScaffoldETHDeploy {

address public worldIdAddr = 0x17B354dD2595411ff79041f930e491A4Df39A278;
uint256 public groupId = 1;
string public appId = "app_22ea9fb73d53333c2997e8f16e60cc6b";
string public action = "registration";

function run() external ScaffoldEthDeployerRunner {
HumanOracleWithWorldIdRegister humanOracle = new HumanOracleWithWorldIdRegister(worldIdAddr, groupId, appId, action);
console.logString(
string.concat(
"HumanOracleWithWorldIdRegister deployed at: ", vm.toString(address(humanOracle))
)
);
}
}
4 changes: 2 additions & 2 deletions packages/foundry/script/DeployWorldIDRegister.s.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "../contracts/WorldIDRegister.sol";
import "../contracts/WorldIdRegister.sol";
import "./DeployHelpers.s.sol";

contract DeployWorldIDRegister is ScaffoldETHDeploy {
Expand All @@ -12,7 +12,7 @@ contract DeployWorldIDRegister is ScaffoldETHDeploy {
string public action = "registration";

function run() external ScaffoldEthDeployerRunner {
WorldIDRegister worldIDRegister = new WorldIDRegister(worldIdAddr, groupId, appId, action);
WorldIdRegister worldIDRegister = new WorldIdRegister(worldIdAddr, groupId, appId, action);
console.logString(
string.concat(
"WorldIDRegister deployed at: ", vm.toString(address(worldIDRegister))
Expand Down
Loading

0 comments on commit 7a78cb5

Please sign in to comment.