From d653425d0a273c3bf7d6881da0c6f55155481955 Mon Sep 17 00:00:00 2001 From: Andres Aiello Date: Wed, 25 Sep 2024 13:28:20 -0300 Subject: [PATCH] Create proof of liveness smart contract --- .../proof-of-liveness/ProofOfLiveness.sol | 60 +++++++++++++++++++ .../zevm-app-contracts/data/addresses.json | 3 +- .../scripts/proof-of-liveness/deploy.ts | 33 ++++++++++ 3 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 packages/zevm-app-contracts/contracts/proof-of-liveness/ProofOfLiveness.sol create mode 100644 packages/zevm-app-contracts/scripts/proof-of-liveness/deploy.ts diff --git a/packages/zevm-app-contracts/contracts/proof-of-liveness/ProofOfLiveness.sol b/packages/zevm-app-contracts/contracts/proof-of-liveness/ProofOfLiveness.sol new file mode 100644 index 0000000..a90fbd3 --- /dev/null +++ b/packages/zevm-app-contracts/contracts/proof-of-liveness/ProofOfLiveness.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +contract ProofOfLiveness { + // 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 24 hours + 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 24 hours + function proveLiveness() external { + uint256 currentTime = block.timestamp; + uint256 lastProofTime = lastProofTimestamp[msg.sender]; + + // Check if the user has proved liveness within the last 24 hours + if (currentTime < lastProofTime + 24 hours) { + 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 24 hours have passed) + function canProveLiveness(address user) external view returns (bool) { + uint256 currentTime = block.timestamp; + return currentTime >= lastProofTimestamp[user] + 24 hours; + } + + // View function to return the liveness proof status for the last 5 periods (each 24 hours long) + function getLastFivePeriodsStatus(address user) external view returns (bool[5] memory) { + uint256 currentTime = block.timestamp; + uint256 lastProofTime = lastProofTimestamp[user]; + + bool[5] memory proofStatus; + uint256 periodDuration = 24 hours; + + for (uint256 i = 0; i < 5; i++) { + // Calculate the start of the period (going back i * 24 hours) + 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; + } +} diff --git a/packages/zevm-app-contracts/data/addresses.json b/packages/zevm-app-contracts/data/addresses.json index 94022ab..8499573 100644 --- a/packages/zevm-app-contracts/data/addresses.json +++ b/packages/zevm-app-contracts/data/addresses.json @@ -8,7 +8,8 @@ "invitationManager": "0x3649C03C472B698213926543456E9c21081e529d", "withdrawERC20": "0xa349B9367cc54b47CAb8D09A95836AE8b4D1d84E", "ZetaXP": "0x5c25b6f4D2b7a550a80561d3Bf274C953aC8be7d", - "InstantRewards": "0x10DfEd4ba9b8F6a1c998E829FfC0325D533c80E3" + "InstantRewards": "0x10DfEd4ba9b8F6a1c998E829FfC0325D533c80E3", + "ProofOfLiveness": "0x2aD64D83827D102FCBBdEb92DEA91fCAB168Cdc2" }, "zeta_mainnet": { "disperse": "0x23ce409Ea60c3d75827d04D9db3d52F3af62e44d", diff --git a/packages/zevm-app-contracts/scripts/proof-of-liveness/deploy.ts b/packages/zevm-app-contracts/scripts/proof-of-liveness/deploy.ts new file mode 100644 index 0000000..5a35f89 --- /dev/null +++ b/packages/zevm-app-contracts/scripts/proof-of-liveness/deploy.ts @@ -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); +});