Skip to content

Commit

Permalink
test: adding staking incentives tests
Browse files Browse the repository at this point in the history
  • Loading branch information
kupermind committed May 22, 2024
1 parent a0c38a8 commit 1daa8ab
Show file tree
Hide file tree
Showing 5 changed files with 262 additions and 18 deletions.
13 changes: 7 additions & 6 deletions contracts/AutonolasGovernance.sol
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
pragma solidity ^0.8.25;

// Importing all the necessary Autonolas governance contracts
import {buOLAS} from "../lib/autonolas-governance/contracts/buOLAS.sol";

Check warning on line 5 in contracts/AutonolasGovernance.sol

View workflow job for this annotation

GitHub Actions / build

imported name buOLAS is not used
import "../lib/autonolas-governance/contracts/OLAS.sol";
import "../lib/autonolas-governance/contracts/GovernorOLAS.sol";
import "../lib/autonolas-governance/contracts/Timelock.sol";
import "../lib/autonolas-governance/contracts/veOLAS.sol";
import {wveOLAS} from "../lib/autonolas-governance/contracts/wveOLAS.sol";
import {OLAS} from "../lib/autonolas-governance/contracts/OLAS.sol";

Check warning on line 6 in contracts/AutonolasGovernance.sol

View workflow job for this annotation

GitHub Actions / build

imported name OLAS is not used
import {GovernorOLAS} from "../lib/autonolas-governance/contracts/GovernorOLAS.sol";

Check warning on line 7 in contracts/AutonolasGovernance.sol

View workflow job for this annotation

GitHub Actions / build

imported name GovernorOLAS is not used
import {Timelock} from "../lib/autonolas-governance/contracts/Timelock.sol";

Check warning on line 8 in contracts/AutonolasGovernance.sol

View workflow job for this annotation

GitHub Actions / build

imported name Timelock is not used
import {veOLAS} from "../lib/autonolas-governance/contracts/veOLAS.sol";

Check warning on line 9 in contracts/AutonolasGovernance.sol

View workflow job for this annotation

GitHub Actions / build

imported name veOLAS is not used
import {wveOLAS} from "../lib/autonolas-governance/contracts/wveOLAS.sol";

Check warning on line 10 in contracts/AutonolasGovernance.sol

View workflow job for this annotation

GitHub Actions / build

imported name wveOLAS is not used
import {VoteWeighting} from "../lib/autonolas-governance/contracts/VoteWeighting.sol";

Check warning on line 11 in contracts/AutonolasGovernance.sol

View workflow job for this annotation

GitHub Actions / build

imported name VoteWeighting is not used
17 changes: 10 additions & 7 deletions contracts/AutonolasRegistries.sol
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
pragma solidity ^0.8.25;

// Importing all the necessary Autonolas registries contracts
import "../lib/autonolas-registries/contracts/AgentRegistry.sol";
import "../lib/autonolas-registries/contracts/ComponentRegistry.sol";
import "../lib/autonolas-registries/contracts/RegistriesManager.sol";
import "../lib/autonolas-registries/contracts/ServiceManager.sol";
import "../lib/autonolas-registries/contracts/ServiceRegistry.sol";
import {AgentRegistry} from "../lib/autonolas-registries/contracts/AgentRegistry.sol";

Check warning on line 5 in contracts/AutonolasRegistries.sol

View workflow job for this annotation

GitHub Actions / build

imported name AgentRegistry is not used
import {ComponentRegistry} from "../lib/autonolas-registries/contracts/ComponentRegistry.sol";

Check warning on line 6 in contracts/AutonolasRegistries.sol

View workflow job for this annotation

GitHub Actions / build

imported name ComponentRegistry is not used
import {RegistriesManager} from "../lib/autonolas-registries/contracts/RegistriesManager.sol";

Check warning on line 7 in contracts/AutonolasRegistries.sol

View workflow job for this annotation

GitHub Actions / build

imported name RegistriesManager is not used
import {ServiceManager} from "../lib/autonolas-registries/contracts/ServiceManager.sol";
import {ServiceRegistry} from "../lib/autonolas-registries/contracts/ServiceRegistry.sol";
import {GnosisSafeMultisig} from "../lib/autonolas-registries/contracts/multisigs/GnosisSafeMultisig.sol";
import {GnosisSafeSameAddressMultisig} from "../lib/autonolas-registries/contracts/multisigs/GnosisSafeSameAddressMultisig.sol";
import {GnosisSafeSameAddressMultisig} from "../lib/autonolas-registries/contracts/multisigs/GnosisSafeSameAddressMultisig.sol";
import {StakingActivityChecker} from "../lib/autonolas-registries/contracts/staking/StakingActivityChecker.sol";
import {StakingFactory} from "../lib/autonolas-registries/contracts/staking/StakingFactory.sol";
import {StakingToken} from "../lib/autonolas-registries/contracts/staking/StakingToken.sol";
8 changes: 6 additions & 2 deletions contracts/AutonolasTokenomics.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
pragma solidity ^0.8.25;

// Importing all the necessary Autonolas tokenomics contracts
import {DonatorBlacklist} from "../lib/autonolas-tokenomics/contracts/DonatorBlacklist.sol";
Expand All @@ -8,4 +8,8 @@ import {Depository} from "../lib/autonolas-tokenomics/contracts/Depository.sol";
import {Dispenser} from "../lib/autonolas-tokenomics/contracts/Dispenser.sol";
import {Tokenomics} from "../lib/autonolas-tokenomics/contracts/Tokenomics.sol";
import {TokenomicsProxy} from "../lib/autonolas-tokenomics/contracts/TokenomicsProxy.sol";
import {Treasury} from "../lib/autonolas-tokenomics/contracts/Treasury.sol";
import {Treasury} from "../lib/autonolas-tokenomics/contracts/Treasury.sol";
import {EthereumDepositProcessor} from "../lib/autonolas-tokenomics/contracts/staking/EthereumDepositProcessor.sol";
import {GnosisDepositProcessorL1} from "../lib/autonolas-tokenomics/contracts/staking/GnosisDepositProcessorL1.sol";
import {GnosisTargetDispenserL2} from "../lib/autonolas-tokenomics/contracts/staking/GnosisTargetDispenserL2.sol";
import {BridgeRelayer} from "../lib/autonolas-tokenomics/contracts/staking/test/BridgeRelayer.sol";
236 changes: 236 additions & 0 deletions test/StakingIncentives.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
/*global describe, beforeEach, it, context*/
const { ethers } = require("hardhat");
const { expect } = require("chai");
const helpers = require("@nomicfoundation/hardhat-network-helpers");

describe("StakingIncentives", async () => {
const initialMint = "1" + "0".repeat(26);
const AddressZero = ethers.constants.AddressZero;
const HashZero = ethers.constants.HashZero;
const defaultHash = "0x" + "5".repeat(64);
const oneYear = 365 * 24 * 3600;
const oneMonth = 86400 * 30;
const oneWeek = 86400 * 7;

Check warning on line 13 in test/StakingIncentives.js

View workflow job for this annotation

GitHub Actions / build

'oneWeek' is assigned a value but never used
const chainId = 31337;
const gnosisChainId = 100;
const defaultWeight = 1000;
const numClaimedEpochs = 1;
const bridgePayload = "0x";
const epochLen = oneMonth;
const delta = 100;

Check warning on line 20 in test/StakingIncentives.js

View workflow job for this annotation

GitHub Actions / build

'delta' is assigned a value but never used
const maxNumClaimingEpochs = 10;
const maxNumStakingTargets = 100;
const maxUint256 = ethers.constants.MaxUint256;

Check warning on line 23 in test/StakingIncentives.js

View workflow job for this annotation

GitHub Actions / build

'maxUint256' is assigned a value but never used
const defaultGasLimit = "2000000";

Check warning on line 24 in test/StakingIncentives.js

View workflow job for this annotation

GitHub Actions / build

'defaultGasLimit' is assigned a value but never used
const retainer = "0x" + "0".repeat(24) + "5".repeat(40);
const livenessRatio = "1" + "0".repeat(16); // 0.01 transaction per second (TPS)
let serviceParams = {
metadataHash: defaultHash,
maxNumServices: 3,
rewardsPerSecond: "1" + "0".repeat(15),
minStakingDeposit: 10,
minNumStakingPeriods: 3,
maxNumInactivityPeriods: 3,
livenessPeriod: 10, // Ten seconds
timeForEmissions: 100,
numAgentInstances: 1,
agentIds: [],
threshold: 0,
configHash: HashZero,
proxyHash: HashZero,
serviceRegistry: AddressZero,
activityChecker: AddressZero
};
const maxInactivity = serviceParams.maxNumInactivityPeriods * serviceParams.livenessPeriod + 1;

Check warning on line 44 in test/StakingIncentives.js

View workflow job for this annotation

GitHub Actions / build

'maxInactivity' is assigned a value but never used

let signers;
let deployer;
let olas;
let ve;
let vw;
let stakingActivityChecker;
let stakingFactory;
let stakingTokenImplementation;
let stakingInstance;
let tokenomics;
let treasury;
let dispenser;
let ethereumDepositProcessor;
let bridgeRelayer;
let gnosisDepositProcessorL1;
let gnosisTargetDispenserL2;
let wormholeDepositProcessorL1;

Check warning on line 62 in test/StakingIncentives.js

View workflow job for this annotation

GitHub Actions / build

'wormholeDepositProcessorL1' is defined but never used

function convertAddressToBytes32(account) {
return ("0x" + "0".repeat(24) + account.slice(2)).toLowerCase();
}

function convertBytes32ToAddress(account) {

Check warning on line 68 in test/StakingIncentives.js

View workflow job for this annotation

GitHub Actions / build

'convertBytes32ToAddress' is defined but never used
return "0x" + account.slice(26);
}

// These should not be in beforeEach.
beforeEach(async () => {
signers = await ethers.getSigners();
deployer = signers[0];

// Governance contracts
const OLAS = await ethers.getContractFactory("OLAS");
olas = await OLAS.deploy();
await olas.deployed();

const VEOLAS = await ethers.getContractFactory("veOLAS");
ve = await VEOLAS.deploy(olas.address, "Voting Escrow OLAS", "veOLAS");
await ve.deployed();

const VoteWeighting = await ethers.getContractFactory("VoteWeighting");
vw = await VoteWeighting.deploy(ve.address);
await vw.deployed();

// Registries contracts
const StakingActivityChecker = await ethers.getContractFactory("StakingActivityChecker");
stakingActivityChecker = await StakingActivityChecker.deploy(livenessRatio);
await stakingActivityChecker.deployed();
serviceParams.activityChecker = stakingActivityChecker.address;

const StakingFactory = await ethers.getContractFactory("StakingFactory");
stakingFactory = await StakingFactory.deploy(AddressZero);
await stakingFactory.deployed();

// For the purpose of this testing, it does not matter which bytecode is specified in the staking contract
// Also, service registry is not important, as the staking capability itself is out of this scope
const bytecode = await ethers.provider.getCode(stakingFactory.address);
const bytecodeHash = ethers.utils.keccak256(bytecode);
serviceParams.proxyHash = bytecodeHash;
serviceParams.serviceRegistry = stakingFactory.address;

const StakingToken = await ethers.getContractFactory("StakingToken");
stakingTokenImplementation = await StakingToken.deploy();
await stakingTokenImplementation.deployed();

// Create a first staking proxy instance
// Note serviceRegistryTokenUtility is also irrelevant for this testing (substituting with deployer)
const initPayload = stakingTokenImplementation.interface.encodeFunctionData("initialize",
[serviceParams, deployer.address, olas.address]);
const stakingTokenAddress = await stakingFactory.getProxyAddress(stakingTokenImplementation.address);
await stakingFactory.createStakingInstance(stakingTokenImplementation.address, initPayload);
stakingInstance = await ethers.getContractAt("StakingToken", stakingTokenAddress);

// Tokenomics contracts
const Dispenser = await ethers.getContractFactory("Dispenser");
dispenser = await Dispenser.deploy(olas.address, deployer.address, deployer.address, vw.address,
retainer, maxNumClaimingEpochs, maxNumStakingTargets);
await dispenser.deployed();

// Set Dispenser in Vote Weighting
vw.changeDispenser(dispenser.address);

const Treasury = await ethers.getContractFactory("Treasury");
treasury = await Treasury.deploy(olas.address, deployer.address, deployer.address, dispenser.address);
await treasury.deployed();

// Update for the correct treasury contract
await dispenser.changeManagers(AddressZero, treasury.address, AddressZero);

const tokenomicsFactory = await ethers.getContractFactory("Tokenomics");
// Deploy master tokenomics contract
const tokenomicsMaster = await tokenomicsFactory.deploy();
await tokenomicsMaster.deployed();

const proxyData = tokenomicsMaster.interface.encodeFunctionData("initializeTokenomics",
[olas.address, treasury.address, deployer.address, dispenser.address, deployer.address, epochLen,
deployer.address, deployer.address, deployer.address, AddressZero]);
// Deploy tokenomics proxy based on the needed tokenomics initialization
const TokenomicsProxy = await ethers.getContractFactory("TokenomicsProxy");
const tokenomicsProxy = await TokenomicsProxy.deploy(tokenomicsMaster.address, proxyData);
await tokenomicsProxy.deployed();

// Get the tokenomics proxy contract
tokenomics = await ethers.getContractAt("Tokenomics", tokenomicsProxy.address);

// Change the tokenomics and treasury addresses in the dispenser to correct ones
await dispenser.changeManagers(tokenomics.address, treasury.address, vw.address);

// Update tokenomics address in treasury
await treasury.changeManagers(tokenomics.address, AddressZero, AddressZero);

// Mint the initial balance
await olas.mint(deployer.address, initialMint);

// Give treasury the minter role
await olas.changeMinter(treasury.address);

// Default Deposit Processor
const EthereumDepositProcessor = await ethers.getContractFactory("EthereumDepositProcessor");
ethereumDepositProcessor = await EthereumDepositProcessor.deploy(olas.address, dispenser.address,
stakingFactory.address, deployer.address);
await ethereumDepositProcessor.deployed();

const BridgeRelayer = await ethers.getContractFactory("BridgeRelayer");
bridgeRelayer = await BridgeRelayer.deploy(olas.address);
await bridgeRelayer.deployed();

const GnosisDepositProcessorL1 = await ethers.getContractFactory("GnosisDepositProcessorL1");
gnosisDepositProcessorL1 = await GnosisDepositProcessorL1.deploy(olas.address, dispenser.address,
bridgeRelayer.address, bridgeRelayer.address, gnosisChainId);
await gnosisDepositProcessorL1.deployed();

const GnosisTargetDispenserL2 = await ethers.getContractFactory("GnosisTargetDispenserL2");
gnosisTargetDispenserL2 = await GnosisTargetDispenserL2.deploy(olas.address,
stakingFactory.address, bridgeRelayer.address, gnosisDepositProcessorL1.address, chainId,
bridgeRelayer.address);
await gnosisTargetDispenserL2.deployed();

// Set the gnosisTargetDispenserL2 address in gnosisDepositProcessorL1
await gnosisDepositProcessorL1.setL2TargetDispenser(gnosisTargetDispenserL2.address);

// Whitelist deposit processors
await dispenser.setDepositProcessorChainIds(
[ethereumDepositProcessor.address, gnosisDepositProcessorL1.address], [chainId, gnosisChainId]);
});

context("Staking incentives", async function () {
it("Claim staking incentives for a single nominee", async () => {
// Take a snapshot of the current state of the blockchain
const snapshot = await helpers.takeSnapshot();

// Set staking fraction to 100%
await tokenomics.changeIncentiveFractions(0, 0, 0, 0, 0, 100);
// Changing staking parameters
await tokenomics.changeStakingParams(50, 10);

// Checkpoint to apply changes
await helpers.time.increase(epochLen);
await tokenomics.checkpoint();

// Unpause the dispenser
await dispenser.setPauseState(0);

// Lock veOLAS
await olas.approve(ve.address, initialMint);
await ve.createLock(ethers.utils.parseEther("1"), oneYear);

// Add a staking instance as a nominee
await vw.addNomineeEVM(stakingInstance.address, chainId);

// Vote for the nominee
const stakingTarget = convertAddressToBytes32(stakingInstance.address);
await vw.voteForNomineeWeights(stakingTarget, chainId, defaultWeight);

// Checkpoint to apply changes
await helpers.time.increase(epochLen);
await tokenomics.checkpoint();

// Claim staking incentives
await dispenser.claimStakingIncentives(numClaimedEpochs, chainId, stakingTarget, bridgePayload);

// Check that the target contract got OLAS
let olasBalance = await olas.balanceOf(stakingInstance.address);
expect(olasBalance).to.gt(0);
console.log(olasBalance);

// Restore to the state of the snapshot
await snapshot.restore();
});
});
});
6 changes: 3 additions & 3 deletions test/TokenomicsLoop.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ describe("Tokenomics integration", async () => {
const retainer = "0x" + "0".repeat(24) + "5".repeat(40);

let erc20Token;
let olaFactory;
let olasFactory;
let depositoryFactory;
let tokenomicsFactory;
let genericBondCalculator;
Expand Down Expand Up @@ -85,7 +85,7 @@ describe("Tokenomics integration", async () => {
*/
beforeEach(async () => {
signers = await ethers.getSigners();
olaFactory = await ethers.getContractFactory("OLAS");
olasFactory = await ethers.getContractFactory("OLAS");
// It does not matter what is the second ERC20 token, let's make it based on OLAS sa well
erc20Token = await ethers.getContractFactory("OLAS");
depositoryFactory = await ethers.getContractFactory("Depository");
Expand Down Expand Up @@ -131,7 +131,7 @@ describe("Tokenomics integration", async () => {

deployer = signers[0];
dai = await erc20Token.deploy();
olas = await olaFactory.deploy();
olas = await olasFactory.deploy();
ve = await veFactory.deploy(olas.address, "Voting Escrow OLAS", "veOLAS");

// Deploy master tokenomics contract
Expand Down

0 comments on commit 1daa8ab

Please sign in to comment.