Skip to content

Commit

Permalink
feat: meme activity checker and staking setup preparation
Browse files Browse the repository at this point in the history
  • Loading branch information
kupermind committed Oct 28, 2024
1 parent 5728fcf commit 25f0b07
Show file tree
Hide file tree
Showing 6 changed files with 244 additions and 1 deletion.
73 changes: 73 additions & 0 deletions contracts/meme/MemeActivityChecker.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

// Meme Factory interface
interface IMemeFactory {
function mapAccountActivities(address multisig) external view returns (uint256);
}

/// @dev Zero address.
error ZeroAddress();

/// @dev Zero value.
error ZeroValue();

/// @title MemeActivityChecker - Smart contract for meme contract interaction service staking activity check
/// @author Aleksandr Kuperman - <[email protected]>
/// @author Andrey Lebedev - <[email protected]>
/// @author David Vilela - <[email protected]>
contract MemeActivityChecker {
// Liveness ratio in the format of 1e18
uint256 public immutable livenessRatio;
// Meme Factory contract address
address public immutable memeFactory;

/// @dev StakingNativeToken initialization.
/// @param _memeFactory Meme Factory contract address.
/// @param _livenessRatio Liveness ratio in the format of 1e18.
constructor(address _memeFactory, uint256 _livenessRatio) {
// Check the zero address
if (_memeFactory == address(0)) {
revert ZeroAddress();
}

// Check for zero value
if (_livenessRatio == 0) {
revert ZeroValue();
}

memeFactory = _memeFactory;
livenessRatio = _livenessRatio;
}

/// @dev Gets service multisig nonces.
/// @param multisig Service multisig address.
/// @return nonces Set of a single service multisig nonce.
function getMultisigNonces(address multisig) external view virtual returns (uint256[] memory nonces) {
nonces = new uint256[](1);
// The nonce is equal to the meme factory contract interaction corresponding to a multisig activity
nonces[0] = IMemeFactory(memeFactory).mapAccountActivities(multisig);
}

/// @dev Checks if the service multisig liveness ratio passes the defined liveness threshold.
/// @notice The formula for calculating the ratio is the following:
/// currentNonce - service multisig nonce at time now (block.timestamp);
/// lastNonce - service multisig nonce at the previous checkpoint or staking time (tsStart);
/// ratio = (currentNonce - lastNonce) / (block.timestamp - tsStart).
/// @param curNonces Current service multisig set of a single nonce.
/// @param lastNonces Last service multisig set of a single nonce.
/// @param ts Time difference between current and last timestamps.
/// @return ratioPass True, if the liveness ratio passes the check.
function isRatioPass(
uint256[] memory curNonces,
uint256[] memory lastNonces,
uint256 ts
) external view virtual returns (bool ratioPass) {
// If the checkpoint was called in the exact same block, the ratio is zero
// If the current nonce is not greater than the last nonce, the ratio is zero
if (ts > 0 && curNonces[0] > lastNonces[0]) {
uint256 ratio = ((curNonces[0] - lastNonces[0]) * 1e18) / ts;
ratioPass = (ratio >= livenessRatio);
}
}
}
77 changes: 77 additions & 0 deletions scripts/deployment/deploy_14_meme_activity_checker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*global process*/

const { ethers } = require("hardhat");
const { LedgerSigner } = require("@anders-t/ethers-ledger");

async function main() {
const fs = require("fs");
const globalsFile = "globals.json";
const dataFromJSON = fs.readFileSync(globalsFile, "utf8");
let parsedData = JSON.parse(dataFromJSON);
const useLedger = parsedData.useLedger;
const derivationPath = parsedData.derivationPath;
const providerName = parsedData.providerName;
const gasPriceInGwei = parsedData.gasPriceInGwei;
const memeFactoryAddress = parsedData.memeFactoryAddress;
const livenessRatio = parsedData.livenessRatio;

let networkURL = parsedData.networkURL;
if (providerName === "polygon") {
if (!process.env.ALCHEMY_API_KEY_MATIC) {
console.log("set ALCHEMY_API_KEY_MATIC env variable");
}
networkURL += process.env.ALCHEMY_API_KEY_MATIC;
} else if (providerName === "polygonAmoy") {
if (!process.env.ALCHEMY_API_KEY_AMOY) {
console.log("set ALCHEMY_API_KEY_AMOY env variable");
return;
}
networkURL += process.env.ALCHEMY_API_KEY_AMOY;
}

const provider = new ethers.providers.JsonRpcProvider(networkURL);
const signers = await ethers.getSigners();

let EOA;
if (useLedger) {
EOA = new LedgerSigner(provider, derivationPath);
} else {
EOA = signers[0];
}
// EOA address
const deployer = await EOA.getAddress();
console.log("EOA is:", deployer);

// Transaction signing and execution
console.log("14. EOA to deploy MemeActivityChecker");
const gasPrice = ethers.utils.parseUnits(gasPriceInGwei, "gwei");
const MemeActivityChecker = await ethers.getContractFactory("MemeActivityChecker");
console.log("You are signing the following transaction: MemeActivityChecker.connect(EOA).deploy()");
const memeActivityChecker = await MemeActivityChecker.connect(EOA).deploy(memeFactoryAddress,
livenessRatio, { gasPrice });
const result = await memeActivityChecker.deployed();

// Transaction details
console.log("Contract deployment: MemeActivityChecker");
console.log("Contract address:", memeActivityChecker.address);
console.log("Transaction:", result.deployTransaction.hash);
// Wait half a minute for the transaction completion
await new Promise(r => setTimeout(r, 30000));

// Writing updated parameters back to the JSON file
parsedData.memeActivityCheckerAddress = memeActivityChecker.address;
fs.writeFileSync(globalsFile, JSON.stringify(parsedData));

// Contract verification
if (parsedData.contractVerification) {
const execSync = require("child_process").execSync;
execSync("npx hardhat verify --constructor-args scripts/deployment/verify_14_meme_activity_checker.js --network " + providerName + " " + memeActivityChecker.address, { encoding: "utf-8" });
}
}

main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"livenessPeriod":"86400",
"timeForEmissions":"2592000",
"numAgentInstances":"1",
"agentIds":["14"],
"agentIds":[],
"threshold":"0",
"configHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
"proxyHash":"0xb89c1b3bdf2cf8827818646bce9a8f6e372885f8c55e5c07acbd307cb133b000",
Expand Down
42 changes: 42 additions & 0 deletions scripts/deployment/globals_base_mainnet_meme_alpha.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"contractVerification":true,
"useLedger":true,
"derivationPath":"m/44'/60'/2'/0/0",
"providerName":"base",
"networkURL":"https://mainnet.base.org",
"gasPriceInGwei":"2",
"bridgeMediatorAddress":"0xE49CB081e8d96920C38aA7AB90cb0294ab4Bc8EA",
"gnosisSafeAddress":"0x69f4D1788e39c87893C980c06EdF4b7f686e2938",
"gnosisSafeProxyFactoryAddress":"0xC22834581EbC8527d974F8a1c97E1bEA4EF910BC",
"fallbackHandlerAddress":"0x017062a1dE2FE6b99BE3d9d37841FeD19F573804",
"olasAddress":"0x54330d28ca3357F294334BDC454a032e7f353416",
"multisigProxyHash130":"0xb89c1b3bdf2cf8827818646bce9a8f6e372885f8c55e5c07acbd307cb133b000",
"serviceRegistryAddress":"0x3C1fF68f5aa342D296d4DEe4Bb1cACCA912D95fE",
"serviceRegistryTokenUtilityAddress":"0x34C895f302D0b5cf52ec0Edd3945321EB0f83dd5",
"serviceManagerTokenAddress":"0x63e66d7ad413C01A7b49C7FF4e3Bb765C4E4bd1b",
"gnosisSafeMultisigImplementationAddress":"0xBb7e1D6Cb6F243D6bdE81CE92a9f2aFF7Fbe7eac",
"stakingTokenAddress":"0xEB5638eefE289691EcE01943f768EDBF96258a80",
"stakingFactoryAddress":"0x1cEe30D08943EB58EFF84DD1AB44a6ee6FEff63a",
"memeFactoryAddress":"",
"livenessRatio":"34722222222222",
"memeActivityCheckerAddress":"",
"stakingParams":
{
"metadataHash":"",
"maxNumServices":"100",
"rewardsPerSecond":"4398148148152",
"minStakingDeposit":"50000000000000000000",
"minNumStakingPeriods":"3",
"maxNumInactivityPeriods":"3",
"livenessPeriod":"86400",
"timeForEmissions":"2592000",
"numAgentInstances":"1",
"agentIds":[],
"threshold":"0",
"configHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
"proxyHash":"0xb89c1b3bdf2cf8827818646bce9a8f6e372885f8c55e5c07acbd307cb133b000",
"serviceRegistry":"0x3C1fF68f5aa342D296d4DEe4Bb1cACCA912D95fE",
"activityChecker":""
},
"stakingTokenInstanceAddress":""
}
40 changes: 40 additions & 0 deletions scripts/deployment/globals_celo_mainnet_meme_alpha.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"contractVerification":true,
"useLedger":true,
"derivationPath":"m/44'/60'/2'/0/0",
"providerName":"celo",
"networkURL":"https://forno.celo.org",
"gasPriceInGwei":"2",
"bridgeMediatorAddress":"0x397125902ED2cA2d42104F621f448A2cE1bC8Fb7",
"gnosisSafeAddress":"0x69f4D1788e39c87893C980c06EdF4b7f686e2938",
"gnosisSafeProxyFactoryAddress":"0xC22834581EbC8527d974F8a1c97E1bEA4EF910BC",
"olasAddress":"0xaCFfAe8e57Ec6E394Eb1b41939A8CF7892DbDc51",
"multisigProxyHash130":"0xb89c1b3bdf2cf8827818646bce9a8f6e372885f8c55e5c07acbd307cb133b000",
"serviceRegistryAddress":"0xE3607b00E75f6405248323A9417ff6b39B244b50",
"serviceRegistryTokenUtilityAddress":"0x3d77596beb0f130a4415df3D2D8232B3d3D31e44",
"serviceManagerTokenAddress":"0x34C895f302D0b5cf52ec0Edd3945321EB0f83dd5",
"stakingTokenAddress":"0xe1E1B286EbE95b39F785d8069f2248ae9C41b7a9",
"stakingFactoryAddress":"0x1c2cD884127b080F940b7546c1e9aaf525b1FA55",
"memeFactoryAddress":"",
"livenessRatio":"34722222222222",
"memeActivityCheckerAddress":"",
"stakingParams":
{
"metadataHash":"",
"maxNumServices":"100",
"rewardsPerSecond":"4398148148152",
"minStakingDeposit":"50000000000000000000",
"minNumStakingPeriods":"3",
"maxNumInactivityPeriods":"3",
"livenessPeriod":"86400",
"timeForEmissions":"2592000",
"numAgentInstances":"1",
"agentIds":[],
"threshold":"0",
"configHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
"proxyHash":"0xb89c1b3bdf2cf8827818646bce9a8f6e372885f8c55e5c07acbd307cb133b000",
"serviceRegistry":"0xE3607b00E75f6405248323A9417ff6b39B244b50",
"activityChecker":""
},
"stakingTokenInstanceAddress":""
}
11 changes: 11 additions & 0 deletions scripts/deployment/verify_14_meme_activity_checker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const fs = require("fs");
const globalsFile = "globals.json";
const dataFromJSON = fs.readFileSync(globalsFile, "utf8");
const parsedData = JSON.parse(dataFromJSON);
const memeFactoryAddress = parsedData.memeFactoryAddress;
const livenessRatio = parsedData.livenessRatio;

module.exports = [
memeFactoryAddress,
livenessRatio
];

0 comments on commit 25f0b07

Please sign in to comment.