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: flowLimit tests live network support #130

Merged
merged 2 commits into from
Oct 26, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
104 changes: 104 additions & 0 deletions contracts/test/utils/FlowLimitTestLiveNetwork.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { IFlowLimit } from '../../interfaces/IFlowLimit.sol';

contract FlowLimitTestLiveNetwork is IFlowLimit {
uint256 internal constant FLOW_LIMIT_SLOT = 0x201b7a0b7c19aaddc4ce9579b7df8d2db123805861bc7763627f13e04d8af42f;
uint256 internal constant PREFIX_FLOW_OUT_AMOUNT = uint256(keccak256('flow-out-amount'));
uint256 internal constant PREFIX_FLOW_IN_AMOUNT = uint256(keccak256('flow-in-amount'));

uint256 internal constant EPOCH_TIME = 60;

function getFlowLimit() public view returns (uint256 flowLimit) {
assembly {
flowLimit := sload(FLOW_LIMIT_SLOT)
}
}

function _setFlowLimit(uint256 flowLimit) internal {
assembly {
sstore(FLOW_LIMIT_SLOT, flowLimit)
}

emit FlowLimitSet(flowLimit);
}

function _getFlowOutSlot(uint256 epoch) internal pure returns (uint256 slot) {
slot = uint256(keccak256(abi.encode(PREFIX_FLOW_OUT_AMOUNT, epoch)));
}

function _getFlowInSlot(uint256 epoch) internal pure returns (uint256 slot) {
slot = uint256(keccak256(abi.encode(PREFIX_FLOW_IN_AMOUNT, epoch)));
}

function getFlowOutAmount() external view returns (uint256 flowOutAmount) {
uint256 epoch = block.timestamp / EPOCH_TIME;
uint256 slot = _getFlowOutSlot(epoch);

assembly {
flowOutAmount := sload(slot)
}
}

function getFlowInAmount() external view returns (uint256 flowInAmount) {
uint256 epoch = block.timestamp / EPOCH_TIME;
uint256 slot = _getFlowInSlot(epoch);

assembly {
flowInAmount := sload(slot)
}
}

function _addFlow(uint256 flowLimit, uint256 slotToAdd, uint256 slotToCompare, uint256 flowAmount) internal {
uint256 flowToAdd;
uint256 flowToCompare;

assembly {
flowToAdd := sload(slotToAdd)
flowToCompare := sload(slotToCompare)
}

if (flowToAdd + flowAmount > flowToCompare + flowLimit) revert FlowLimitExceeded();
if (flowAmount > flowLimit) revert FlowLimitExceeded();

assembly {
sstore(slotToAdd, add(flowToAdd, flowAmount))
}
}

function _addFlowOut(uint256 flowOutAmount) internal {
uint256 flowLimit = getFlowLimit();
if (flowLimit == 0) return;

uint256 epoch = block.timestamp / EPOCH_TIME;
uint256 slotToAdd = _getFlowOutSlot(epoch);
uint256 slotToCompare = _getFlowInSlot(epoch);

_addFlow(flowLimit, slotToAdd, slotToCompare, flowOutAmount);
}

function _addFlowIn(uint256 flowInAmount) internal {
uint256 flowLimit = getFlowLimit();
if (flowLimit == 0) return;

uint256 epoch = block.timestamp / EPOCH_TIME;
uint256 slotToAdd = _getFlowInSlot(epoch);
uint256 slotToCompare = _getFlowOutSlot(epoch);

_addFlow(flowLimit, slotToAdd, slotToCompare, flowInAmount);
}

function setFlowLimit(uint256 flowLimit) external {
_setFlowLimit(flowLimit);
}

function addFlowIn(uint256 flowInAmount) external {
_addFlowIn(flowInAmount);
}

function addFlowOut(uint256 flowOutAmount) external {
_addFlowOut(flowOutAmount);
}
}
21 changes: 14 additions & 7 deletions test/UtilsTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const { Wallet, Contract } = ethers;
const { AddressZero } = ethers.constants;
const { defaultAbiCoder, arrayify, toUtf8Bytes, hexlify } = ethers.utils;
const { expect } = chai;
const { getRandomBytes32, expectRevert } = require('./utils');
const { getRandomBytes32, expectRevert, isHardhat, waitFor } = require('./utils');
const { deployContract } = require('../scripts/deploy');

const ImplemenationTest = require('../artifacts/contracts/test/utils/ImplementationTest.sol/ImplementationTest.json');
Expand Down Expand Up @@ -177,18 +177,25 @@ describe('ExpressCallHandler', () => {

describe('FlowLimit', async () => {
let test;
const flowLimit = 5;
const flowLimit = isHardhat ? 5 : 2;

before(async () => {
test = await deployContract(ownerWallet, 'FlowLimitTest');
test = isHardhat
? await deployContract(ownerWallet, 'FlowLimitTest')
: await deployContract(ownerWallet, 'FlowLimitTestLiveNetwork');
});

async function nextEpoch() {
const latest = Number(await time.latest());
const epoch = 6 * 3600;
const next = (Math.floor(latest / epoch) + 1) * epoch;
const epoch = isHardhat ? 6 * 3600 : 60;

await time.increaseTo(next);
if (isHardhat) {
const latest = Number(await time.latest());
const next = (Math.floor(latest / epoch) + 1) * epoch;

await time.increaseTo(next);
} else {
await waitFor(epoch);
}
}

it('Should calculate hardcoded constants correctly', async () => {
Expand Down
13 changes: 13 additions & 0 deletions test/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ const getGasOptions = () => {
return network.config.blockGasLimit ? { gasLimit: network.config.blockGasLimit.toString() } : { gasLimit: 5e6 }; // defaults to 5M gas for revert tests to work correctly
};

const isHardhat = network.name === 'hardhat';

const expectRevert = async (txFunc, contract, error) => {
if (network.config.skipRevertTests) {
await expect(txFunc(getGasOptions())).to.be.reverted;
Expand All @@ -18,6 +20,15 @@ const expectRevert = async (txFunc, contract, error) => {
}
};

const waitFor = async (timeDelay) => {
if (isHardhat) {
await network.provider.send('evm_increaseTime', [timeDelay]);
await network.provider.send('evm_mine');
} else {
await new Promise((resolve) => setTimeout(resolve, timeDelay * 1000));
}
};

const getChainId = () => {
return network.config.chainId;
};
Expand All @@ -26,5 +37,7 @@ module.exports = {
getRandomBytes32,
getChainId,
getGasOptions,
isHardhat,
expectRevert,
waitFor,
};
Loading