Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Create proof of liveness smart contract #190

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract ProofOfLiveness {
uint256 constant PROOF_PERIOD = 24 hours;
uint256 constant LAST_PERIODS_LENGTH = 5;

// Mapping to track the last time the user proved liveness
mapping(address => uint256) public lastProofTimestamp;

// Custom error for when a user has already proved liveness within the last PROOF_PERIOD
error ProofWithinLast24Hours(uint256 lastProofTime);

// Event to log when liveness is proved
event LivenessProved(address indexed user, uint256 proofTimestamp);

// The function to prove liveness, can only be called once every PROOF_PERIOD
function proveLiveness() external {
uint256 currentTime = block.timestamp;
uint256 lastProofTime = lastProofTimestamp[msg.sender];

// Check if the user has proved liveness within the last PROOF_PERIOD
if (currentTime < lastProofTime + PROOF_PERIOD) {
revert ProofWithinLast24Hours(lastProofTime);
}

// Update the last proof timestamp for the user
lastProofTimestamp[msg.sender] = currentTime;

// Emit an event to track the liveness proof
emit LivenessProved(msg.sender, currentTime);
}

// Helper function to check if a user can prove liveness (returns true if PROOF_PERIOD have passed)
function canProveLiveness(address user) external view returns (bool) {
uint256 currentTime = block.timestamp;
return currentTime >= lastProofTimestamp[user] + PROOF_PERIOD;
}

// View function to return the liveness proof status for the last LAST_PERIODS_LENGTH periods (each PROOF_PERIOD long)
function getLastPeriodsStatus(address user) external view returns (bool[LAST_PERIODS_LENGTH] memory) {
uint256 currentTime = block.timestamp;
uint256 lastProofTime = lastProofTimestamp[user];

bool[LAST_PERIODS_LENGTH] memory proofStatus;
Fixed Show fixed Hide fixed
uint256 periodDuration = PROOF_PERIOD;

for (uint256 i = 0; i < LAST_PERIODS_LENGTH; i++) {
// Calculate the start of the period (going back i * PROOF_PERIOD)
uint256 periodStart = currentTime - (i * periodDuration);
uint256 periodEnd = periodStart - periodDuration;

// If the last proof timestamp falls within this period, mark it as true
if (lastProofTime >= periodEnd && lastProofTime < periodStart) {
proofStatus[i] = true;
} else {
proofStatus[i] = false;
}
}

return proofStatus;
}
Fixed Show fixed Hide fixed
andresaiello marked this conversation as resolved.
Show resolved Hide resolved
}
3 changes: 2 additions & 1 deletion packages/zevm-app-contracts/data/addresses.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"invitationManager": "0x3649C03C472B698213926543456E9c21081e529d",
"withdrawERC20": "0xa349B9367cc54b47CAb8D09A95836AE8b4D1d84E",
"ZetaXP": "0x5c25b6f4D2b7a550a80561d3Bf274C953aC8be7d",
"InstantRewards": "0x10DfEd4ba9b8F6a1c998E829FfC0325D533c80E3"
"InstantRewards": "0x10DfEd4ba9b8F6a1c998E829FfC0325D533c80E3",
"ProofOfLiveness": "0x2aD64D83827D102FCBBdEb92DEA91fCAB168Cdc2"
},
"zeta_mainnet": {
"disperse": "0x23ce409Ea60c3d75827d04D9db3d52F3af62e44d",
Expand Down
33 changes: 33 additions & 0 deletions packages/zevm-app-contracts/scripts/proof-of-liveness/deploy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { isProtocolNetworkName } from "@zetachain/protocol-contracts";
import { ethers, network } from "hardhat";

import { ProofOfLiveness__factory } from "../../typechain-types";
import { saveAddress } from "../address.helpers";
import { verifyContract } from "../explorer.helpers";

const networkName = network.name;

const deployProofOfLiveness = async () => {
if (!isProtocolNetworkName(networkName)) throw new Error("Invalid network name");

const ProofOfLivenessFactory = (await ethers.getContractFactory("ProofOfLiveness")) as ProofOfLiveness__factory;
const ProofOfLiveness = await ProofOfLivenessFactory.deploy();

await ProofOfLiveness.deployed();

console.log("ProofOfLiveness deployed to:", ProofOfLiveness.address);

saveAddress("ProofOfLiveness", ProofOfLiveness.address, networkName);

await verifyContract(ProofOfLiveness.address, []);
};

const main = async () => {
if (!isProtocolNetworkName(networkName)) throw new Error("Invalid network name");
await deployProofOfLiveness();
};

main().catch((error) => {
console.error(error);
process.exit(1);
});
andresaiello marked this conversation as resolved.
Show resolved Hide resolved
Loading