Skip to content

Commit

Permalink
Merge branch 'sbt' of github.com:VenusProtocol/venus-protocol into sbt
Browse files Browse the repository at this point in the history
  • Loading branch information
narayanprusty committed Sep 13, 2023
2 parents f5e3221 + 9571e83 commit 8af2567
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 35 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ jobs:
if: github.event_name == 'pull_request'
with:
recreate: true
path: code-coverage-results.md
path: code-coverage-results.md

lint:
name: Lint
Expand Down
8 changes: 8 additions & 0 deletions contracts/Tokens/Prime/Prime.sol
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,14 @@ contract Prime is IIncomeDestination, AccessControlledV8, PausableUpgradeable, P
}
}

/**
* @notice Retrieves an array of all available markets
* @return An array of addresses representing all available markets
*/
function getAllMarkets() external view returns (address[] memory) {
return allMarkets;
}

function _accrueInterestAndUpdateScore(address user) internal {
address[] storage _allMarkets = allMarkets;
for (uint i = 0; i < _allMarkets.length; i++) {
Expand Down
9 changes: 7 additions & 2 deletions contracts/Tokens/Prime/PrimeLiquidityProvider.sol
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ contract PrimeLiquidityProvider is AccessControlledV8, PausableUpgradeable {
/// @notice Thrown when distribution speed is greater than MAX_DISTRIBUTION_SPEED
error InvalidDistributionSpeed(uint256 speed, uint256 maxSpeed);

/// @notice Thrown when caller is not the desired caller
error InvalidCaller();

/// @notice Thrown when token is initialized
error TokenAlreadyInitialized(address token);

Expand Down Expand Up @@ -176,6 +179,7 @@ contract PrimeLiquidityProvider is AccessControlledV8, PausableUpgradeable {
* @custom:error Throw InvalidArguments on Zero address(token)
*/
function releaseFunds(address token_) external {
if (msg.sender != prime) revert InvalidCaller();
if (paused()) {
revert FundsTransferIsPaused();
}
Expand Down Expand Up @@ -224,9 +228,10 @@ contract PrimeLiquidityProvider is AccessControlledV8, PausableUpgradeable {
uint256 distributionSpeed = tokenDistributionSpeeds[token_];
uint256 balance = IERC20Upgradeable(token_).balanceOf(address(this));

if (distributionSpeed > 0 && (balance - tokenAmountAccrued[token_]) > 0) {
uint256 balanceDiff = balance - tokenAmountAccrued[token_];
if (distributionSpeed > 0 && balanceDiff > 0) {
uint256 accruedSinceUpdate = deltaBlocks * distributionSpeed;
uint256 tokenAccrued = (balance <= accruedSinceUpdate ? balance : accruedSinceUpdate);
uint256 tokenAccrued = (balanceDiff <= accruedSinceUpdate ? balanceDiff : accruedSinceUpdate);

tokenAmountAccrued[token_] += tokenAccrued;
emit TokensAccrued(token_, tokenAccrued);
Expand Down
2 changes: 1 addition & 1 deletion contracts/Tokens/Prime/PrimeStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ contract PrimeStorageV1 {
mapping(address => mapping(address => Interest)) public interests;

/// @notice A list of boosted markets
address[] public allMarkets;
address[] internal allMarkets;

/// @notice numberator of alpha. Ex: if alpha is 0.5 then this will be 1
uint128 public alphaNumerator;
Expand Down
2 changes: 1 addition & 1 deletion hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import { ethers } from "ethers";
import fs from "fs";
import "hardhat-deploy";
import { HardhatUserConfig, task } from "hardhat/config";
import "solidity-docgen";
import "solidity-coverage";
import "solidity-docgen";

require("hardhat-contract-sizer");
require("dotenv").config();
Expand Down
54 changes: 28 additions & 26 deletions tests/hardhat/Prime/Prime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
IAccessControlManager,
IProtocolShareReserve,
InterestRateModelHarness,
Prime,
PrimeLiquidityProvider,
PrimeLiquidityProvider__factory,
PrimeScenario,
Expand All @@ -25,7 +24,6 @@ import {
XVSVault,
XVSVaultScenario,
} from "../../../typechain";
import exp from "constants";

const { expect } = chai;
chai.use(smock.matchers);
Expand Down Expand Up @@ -186,8 +184,9 @@ async function deployProtocol(): Promise<SetupProtocolFixture> {
const primeLiquidityProviderFactory = await ethers.getContractFactory("PrimeLiquidityProvider");
const primeLiquidityProvider = await upgrades.deployProxy(
primeLiquidityProviderFactory,
[accessControl.address, [], []], {}
)
[accessControl.address, [], []],
{},
);

const primeFactory = await ethers.getContractFactory("PrimeScenario");
const prime: PrimeScenario = await upgrades.deployProxy(
Expand Down Expand Up @@ -235,7 +234,7 @@ async function deployProtocol(): Promise<SetupProtocolFixture> {
xvsStore,
prime,
protocolShareReserve,
primeLiquidityProvider
primeLiquidityProvider,
};
}

Expand All @@ -251,13 +250,14 @@ describe("PrimeScenario Token", () => {

describe("protocol setup", () => {
let comptroller: MockContract<ComptrollerMock>;
let prime: PrimeScenario;
let vusdt: VBep20Harness;
let veth: VBep20Harness;
let usdt: BEP20Harness;
let eth: BEP20Harness;

beforeEach(async () => {
({ comptroller, vusdt, veth, usdt, eth } = await loadFixture(deployProtocol));
({ comptroller, vusdt, veth, usdt, eth, prime } = await loadFixture(deployProtocol));

await eth.connect(user1).approve(veth.address, bigNumber18.mul(90));
await veth.connect(user1).mint(bigNumber18.mul(90));
Expand All @@ -281,6 +281,12 @@ describe("PrimeScenario Token", () => {
expect(await usdt.balanceOf(user1.getAddress())).to.be.gt(0);
expect(await eth.balanceOf(user2.getAddress())).to.be.gt(0);
});

it("get markets in prime", async () => {
const [market1, market2] = await prime.getAllMarkets();
expect(market1).to.be.equal(vusdt.address);
expect(market2).to.be.equal(veth.address);
});
});

describe("mint and burn", () => {
Expand Down Expand Up @@ -776,21 +782,18 @@ describe("PrimeScenario Token", () => {
let vusdt: VBep20Harness;
let veth: VBep20Harness;
let vmatic: VBep20Harness;
let usdt: BEP20Harness;
let eth: BEP20Harness;
let matic: BEP20Harness;
let xvsVault: XVSVault;
let xvs: XVS;
let oracle: FakeContract<ResilientOracleInterface>;
let protocolShareReserve: FakeContract<IProtocolShareReserve>;
let primeLiquidityProvider: PrimeLiquidityProvider;

beforeEach(async () => {
const [wallet, user1, user2, user3] = await ethers.getSigners();
const [wallet, user1] = await ethers.getSigners();

({ comptroller, prime, vusdt, veth, usdt, eth, xvsVault, xvs, oracle, protocolShareReserve, primeLiquidityProvider } = await loadFixture(
deployProtocol,
));
({ comptroller, prime, vusdt, veth, xvsVault, xvs, oracle, protocolShareReserve, primeLiquidityProvider } =
await loadFixture(deployProtocol));

await protocolShareReserve.getUnreleasedFunds.returns("0");
await protocolShareReserve.getPercentageDistribution.returns("100");
Expand Down Expand Up @@ -821,11 +824,10 @@ describe("PrimeScenario Token", () => {
BigNumber.from(18),
wallet.address,
)) as VBep20Harness;

const half = convertToUnit("0.5", 18);
await vmatic._setReserveFactor(bigNumber16.mul(20));
await comptroller._supportMarket(vmatic.address);


oracle.getUnderlyingPrice.returns((vToken: string) => {
if (vToken == vusdt.address) {
Expand Down Expand Up @@ -856,20 +858,20 @@ describe("PrimeScenario Token", () => {
const speed = convertToUnit(1, 18);
await primeLiquidityProvider.setTokensDistributionSpeed([matic.address], [speed]);
await matic.transfer(primeLiquidityProvider.address, bigNumber18.mul(10000));
})
});

it("claim interest", async () => {
let interest = await prime.interests(vmatic.address, user1.getAddress());
expect(interest.score).to.be.equal("948683298050513937723");
expect(interest.accrued).to.be.equal(0);
expect(interest.rewardIndex).to.be.equal(0);

let plpAccrued = await primeLiquidityProvider.tokenAmountAccrued(matic.address)
let plpAccrued = await primeLiquidityProvider.tokenAmountAccrued(matic.address);
expect(plpAccrued).to.be.equal(0);

await mine(100);
await primeLiquidityProvider.accrueTokens(matic.address);
plpAccrued = await primeLiquidityProvider.tokenAmountAccrued(matic.address)
plpAccrued = await primeLiquidityProvider.tokenAmountAccrued(matic.address);
expect(plpAccrued).to.be.equal(bigNumber18.mul(102)); // (1 * 100) + 2 = 102

await prime.accrueInterest(vmatic.address);
Expand Down Expand Up @@ -897,17 +899,17 @@ describe("PrimeScenario Token", () => {
await prime["claimInterest(address,address)"](vmatic.address, user1.getAddress());
const afterBalance = await matic.balanceOf(user1.getAddress());
// 103999999999999999163 + 1000000000000000000 = 104999999999999998571
expect(afterBalance).to.be.equal("104999999999999998571");
})
expect(afterBalance).to.be.equal("104999999999999998571");
});

it("APR Estimation", async () => {
const apr = await prime.calculateAPR(vmatic.address, user1.getAddress());
expect(apr.supplyAPR.toString()).to.be.equal("1168000000");
})
});

it("Hypothetical APR Estimation", async () => {
let apr = await prime.estimateAPR(
vmatic.address,
vmatic.address,
user1.getAddress(),
bigNumber18.mul(100),
bigNumber18.mul(100),
Expand All @@ -917,7 +919,7 @@ describe("PrimeScenario Token", () => {
expect(apr.borrowAPR.toString()).to.be.equal("525600000");

apr = await prime.estimateAPR(
vmatic.address,
vmatic.address,
user1.getAddress(),
bigNumber18.mul(100),
bigNumber18.mul(50),
Expand All @@ -927,14 +929,14 @@ describe("PrimeScenario Token", () => {
expect(apr.borrowAPR.toString()).to.be.equal("700800000");

apr = await prime.estimateAPR(
vmatic.address,
vmatic.address,
user1.getAddress(),
bigNumber18.mul(100),
bigNumber18.mul(0),
bigNumber18.mul(1000000),
);
expect(apr.supplyAPR.toString()).to.be.equal("0");
expect(apr.borrowAPR.toString()).to.be.equal("1051200000");
})
});
});
});
25 changes: 21 additions & 4 deletions tests/hardhat/Prime/PrimeLiquidityProvider.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { FakeContract, MockContract, smock } from "@defi-wonderland/smock";
import { loadFixture, mine } from "@nomicfoundation/hardhat-network-helpers";
import { impersonateAccount, loadFixture, mine } from "@nomicfoundation/hardhat-network-helpers";
import { expect } from "chai";
import { parseUnits } from "ethers/lib/utils";
import { ethers, upgrades } from "hardhat";
Expand Down Expand Up @@ -280,18 +280,35 @@ describe("PrimeLiquidityProvider: tests", () => {
await mine(10);
});

it("Revert on funds ransfer Paused", async () => {
it("Revert on funds transfer Paused", async () => {
const [wallet] = await ethers.getSigners();
await primeLiquidityProvider.pauseFundsTransfer();

const tx = primeLiquidityProvider.releaseFunds(tokenA.address);
await impersonateAccount(prime.address);
const primeSigner = await ethers.provider.getSigner(prime.address);
await wallet.sendTransaction({ to: prime.address, value: ethers.utils.parseEther("10") });

const tx = primeLiquidityProvider.connect(primeSigner).releaseFunds(tokenA.address);

await expect(tx).to.be.to.be.revertedWithCustomError(primeLiquidityProvider, "FundsTransferIsPaused");
});

it("Revert on invalid caller", async () => {
const tx = primeLiquidityProvider.releaseFunds(tokenA.address);

await expect(tx).to.be.to.be.revertedWithCustomError(primeLiquidityProvider, "InvalidCaller");
});

it("Release funds success", async () => {
const [wallet] = await ethers.getSigners();

const lastAccruedBlockTokenA = await primeLiquidityProvider.lastAccruedBlock(tokenB.address);

const tx = await primeLiquidityProvider.releaseFunds(tokenA.address);
await impersonateAccount(prime.address);
const primeSigner = await ethers.provider.getSigner(prime.address);
await wallet.sendTransaction({ to: prime.address, value: ethers.utils.parseEther("10") });

const tx = await primeLiquidityProvider.connect(primeSigner).releaseFunds(tokenA.address);
tx.wait();

const currentBlockTokenA = await primeLiquidityProvider.getBlockNumber();
Expand Down

0 comments on commit 8af2567

Please sign in to comment.