Skip to content
This repository has been archived by the owner on May 24, 2024. It is now read-only.

Modify mock chainlink oracle with ownership for public testnet deployment and add test erc20 token faucet with unit tests #175

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
4 changes: 3 additions & 1 deletion addresses/euler-addresses-goerli.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@
"CRV": "0x87351b560ebc1810CF33cBA7A0b508e2Cf36e821"
},
"eulerGeneralView": "0x486492546998494C224b294aE8c5a2982946220B",
"eulerSimpleLens": "0x62626a0f051B547b3182e55D1Eba667138790D8D",
"euler": "0x931172BB95549d0f29e10ae2D079ABA3C63318B3",
"installer": "0xB21fb96025c2b7F618ba9D3ae955D20Fa303b2D2",
"markets": "0x3EbC39b84B1F856fAFE9803A9e1Eae7Da016Da36",
"liquidation": "0x66326c072283feE63E1C3feF9BD024F8697EC1BB",
"governance": "0x496A8344497875D0D805167874f2f938aEa15600",
"exec": "0x4b62EB6797526491eEf6eF36D3B9960E5d66C394"
"exec": "0x4b62EB6797526491eEf6eF36D3B9960E5d66C394",
"testERC20TokenFaucet": "0x1215396CB53774dCE60978d7237F32042cF3a1db"
}
15 changes: 13 additions & 2 deletions contracts/test/MockEACAggregatorProxy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ contract MockAggregatorProxy {
uint80 answeredInRound; // The round ID of the round in which the answer was computed.
}

address public owner;
string constant description_ = "Mock Aggregator";
uint256 constant version_ = 1;
uint8 public decimals_;
Expand All @@ -18,14 +19,24 @@ contract MockAggregatorProxy {

constructor(uint8 _decimals) {
decimals_ = _decimals;
owner = msg.sender;
}

function mockSetData(Data calldata data) external {
modifier onlyOwner() {
require(msg.sender == owner, "unauthorized");
_;
}

function changeOwner(address newOwner) external onlyOwner {
owner = newOwner;
}

function mockSetData(Data calldata data) external onlyOwner {
data_[data.roundId] = data;
currentRoundId_ = data.roundId;
}

function mockSetValidAnswer(int256 answer) external {
function mockSetValidAnswer(int256 answer) external onlyOwner {
currentRoundId_++;
data_[currentRoundId_] =
Data(
Expand Down
50 changes: 50 additions & 0 deletions contracts/test/TestERC20TokenFaucet.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.8.0;

interface IERC20 {
function transfer(address recipient, uint256 amount) external returns (bool);
function decimals() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
}

contract TestERC20TokenFaucet {
address public owner;
mapping(address => uint256) thresholds;

constructor() {
owner = msg.sender;
}

function withdraw(address underlying) external {
uint256 balance = IERC20(underlying).balanceOf(msg.sender);
uint256 amount = getThreshold(underlying);
require(balance < amount, "withdraw: balance not below threshold");
IERC20(underlying).transfer(msg.sender, amount - balance);
}

function getThreshold(address underlying) public view returns(uint256) {
return thresholds[underlying];
}

// Owner functions

modifier onlyOwner {
require(msg.sender == owner, "unauthorized");
_;
}

function setThreshold(address underlying, uint256 _threshold) external onlyOwner {
require(_threshold > 0, "setThreshold: threshold must be greater than zero");
thresholds[underlying] = _threshold;
}

function reduceFaucetBalance(address underlying, uint256 amount) external onlyOwner {
if (amount == type(uint256).max) {
uint balance = IERC20(underlying).balanceOf(address(this));
IERC20(underlying).transfer(msg.sender, balance);
} else {
IERC20(underlying).transfer(msg.sender, amount);
}
}
}
65 changes: 65 additions & 0 deletions test/chainlinkPriceFeed.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,71 @@ et.testSet({
]
})

.test({
desc: "set the correct owner upon deployment",
actions: ctx => [
{ call: 'AggregatorTST.owner', args: [], assertEql: ctx.wallet.address, },
]
})

.test({
desc: "reverts if non-owner attempts to set price via mockSetValidAnswer",
actions: ctx => [
{ call: 'AggregatorTST.latestAnswer', args: [], assertEql: 0, },

{ from: ctx.wallet2, send: 'AggregatorTST.mockSetValidAnswer', args: [et.eth('1')],
expectError: 'unauthorized',
},

{ call: 'AggregatorTST.latestAnswer', args: [], assertEql: 0, },

{ from: ctx.wallet, send: 'AggregatorTST.mockSetValidAnswer', args: [et.eth('1')], },

{ call: 'AggregatorTST.latestAnswer', args: [], assertEql: et.eth('1'), },
]
})

.test({
desc: "reverts if non-owner attempts to set price via mockSetData",
actions: ctx => [
{ action: 'cb', cb: async () => {
let latestAnswer = await ctx.contracts.AggregatorTST.latestAnswer();
et.expect(latestAnswer).to.equal(0);

let errMsg = '';
try {
await ctx.contracts.AggregatorTST.connect(ctx.wallet2).mockSetData([1, 123456, 0, 0, 0]);
latestAnswer = await ctx.contracts.AggregatorTST.latestAnswer();
et.expect(latestAnswer).to.equal(0);

await ctx.contracts.AggregatorTST.connect(ctx.wallet).mockSetData([1, 123456, 0, 0, 0]);
latestAnswer = await ctx.contracts.AggregatorTST.latestAnswer();
et.expect(latestAnswer).to.equal(123456);
} catch (e) {
errMsg = e.message;
}
et.expect(errMsg).to.contains('unauthorized');
}},
]
})

.test({
desc: "reverts if non-owner attempts to change owner",
actions: ctx => [
{ call: 'AggregatorTST.owner', args: [], assertEql: ctx.wallet.address, },

{ from: ctx.wallet2, send: 'AggregatorTST.changeOwner', args: [ctx.wallet2.address],
expectError: 'unauthorized',
},

{ call: 'AggregatorTST.owner', args: [], assertEql: ctx.wallet.address, },

{ from: ctx.wallet, send: 'AggregatorTST.changeOwner', args: [ctx.wallet2.address], },

{ call: 'AggregatorTST.owner', args: [], assertEql: ctx.wallet2.address, },
]
})

.test({
desc: "chainlink pricing setup and price fetch",
actions: ctx => [
Expand Down
1 change: 1 addition & 0 deletions test/lib/eTestLib.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ const contractNames = [
// Testing

'TestERC20',
'TestERC20TokenFaucet',
'MockUniswapV3Factory',
'EulerGeneralView',
'InvariantChecker',
Expand Down
194 changes: 194 additions & 0 deletions test/tokenFaucet.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
const et = require('./lib/eTestLib');

et.testSet({
desc: "ERC20 test token faucet",
preActions: ctx => [
{ action: 'cb', cb: async () => {
// deploy faucet

ctx.contracts.TestERC20Faucet = await (await ctx.factories.TestERC20TokenFaucet.deploy()).deployed();
}}
]
})


.test({
desc: "only owner can set threshold",
actions: ctx => [
{ from: ctx.wallet2, send: 'TestERC20Faucet.setThreshold', args: [ctx.contracts.tokens.TST.address, 2],
expectError: 'unauthorized',
},

{ send: 'TestERC20Faucet.setThreshold', args: [ctx.contracts.tokens.TST.address, 2], },

{ call: 'TestERC20Faucet.getThreshold', args: [ctx.contracts.tokens.TST.address], assertEql: 2, },
],
})


.test({
desc: "owner can set threshold for multiple tokens",
actions: ctx => [
{ send: 'TestERC20Faucet.setThreshold', args: [ctx.contracts.tokens.TST.address, 2], },

{ call: 'TestERC20Faucet.getThreshold', args: [ctx.contracts.tokens.TST.address], assertEql: 2, },

{ send: 'TestERC20Faucet.setThreshold', args: [ctx.contracts.tokens.TST2.address, 12], },

{ call: 'TestERC20Faucet.getThreshold', args: [ctx.contracts.tokens.TST2.address], assertEql: 12, },
],
})


.test({
desc: "zero threshold reverts",
actions: ctx => [
{ send: 'TestERC20Faucet.setThreshold', args: [ctx.contracts.tokens.TST.address, 0],
expectError: 'setThreshold: threshold must be greater than zero',
},
],
})


.test({
desc: "only owner can reduce faucet balance",
actions: ctx => [
{ send: 'tokens.TST.mint', args: [ctx.contracts.TestERC20Faucet.address, 100], },

{ call: 'tokens.TST.balanceOf', args: [ctx.contracts.TestERC20Faucet.address], assertEql: 100, },

{ call: 'tokens.TST.balanceOf', args: [ctx.wallet.address], assertEql: 0, },

{ from: ctx.wallet2, send: 'TestERC20Faucet.reduceFaucetBalance', args: [ctx.contracts.tokens.TST.address, 2],
expectError: 'unauthorized',
},

{ send: 'TestERC20Faucet.reduceFaucetBalance', args: [ctx.contracts.tokens.TST.address, 2], },

{ call: 'tokens.TST.balanceOf', args: [ctx.contracts.TestERC20Faucet.address], assertEql: 98, },

{ call: 'tokens.TST.balanceOf', args: [ctx.wallet.address], assertEql: 2, },
],
})


.test({
desc: "owner can reduce faucet balance to zero using max uint256",
actions: ctx => [
{ send: 'tokens.TST.mint', args: [ctx.contracts.TestERC20Faucet.address, 100], },

{ call: 'tokens.TST.balanceOf', args: [ctx.contracts.TestERC20Faucet.address], assertEql: 100, },

{ call: 'tokens.TST.balanceOf', args: [ctx.wallet.address], assertEql: 0, },

{ send: 'TestERC20Faucet.reduceFaucetBalance', args: [ctx.contracts.tokens.TST.address, et.MaxUint256], },

{ call: 'tokens.TST.balanceOf', args: [ctx.contracts.TestERC20Faucet.address], assertEql: 0, },

{ call: 'tokens.TST.balanceOf', args: [ctx.wallet.address], assertEql: 100, },
],
})


.test({
desc: "withdraw only tops up user balance and does not issue full threshold",
actions: ctx => [
{ send: 'TestERC20Faucet.setThreshold', args: [ctx.contracts.tokens.TST.address, et.eth(1)], },

{ call: 'TestERC20Faucet.getThreshold', args: [ctx.contracts.tokens.TST.address], assertEql: et.eth(1), },

{ call: 'tokens.TST.balanceOf', args: [ctx.wallet2.address], assertEql: 0, },

{ send: 'tokens.TST.mint', args: [ctx.contracts.TestERC20Faucet.address, et.eth(50)], },

{ from: ctx.wallet2, send: 'TestERC20Faucet.withdraw', args: [ctx.contracts.tokens.TST.address, ], },

{ call: 'tokens.TST.balanceOf', args: [ctx.wallet2.address], assertEql: et.eth(1), },

{ from: ctx.wallet2, send: 'tokens.TST.transfer', args: [ctx.wallet3.address, et.eth(0.5)], },

{ call: 'tokens.TST.balanceOf', args: [ctx.wallet3.address], assertEql: et.eth(0.5), },
{ call: 'tokens.TST.balanceOf', args: [ctx.wallet2.address], assertEql: et.eth(0.5), },

{ from: ctx.wallet2, send: 'TestERC20Faucet.withdraw', args: [ctx.contracts.tokens.TST.address, ], },
{ call: 'tokens.TST.balanceOf', args: [ctx.wallet3.address], assertEql: et.eth(0.5), },
{ call: 'tokens.TST.balanceOf', args: [ctx.wallet2.address], assertEql: et.eth(1), },
],
})


.test({
desc: "withdraw reverts if threshold is not set",
actions: ctx => [
{ call: 'tokens.TST.balanceOf', args: [ctx.wallet2.address], assertEql: 0, },

{ send: 'tokens.TST.mint', args: [ctx.contracts.TestERC20Faucet.address, et.eth(50)], },

{ from: ctx.wallet2, send: 'TestERC20Faucet.withdraw', args: [ctx.contracts.tokens.TST.address, ],
expectError: 'withdraw: balance not below threshold',
},

{ call: 'tokens.TST.balanceOf', args: [ctx.wallet2.address], assertEql: 0, },
],
})


.test({
desc: "withdraw reverts if faucet balance is below withdrawal amount",
actions: ctx => [
{ call: 'tokens.TST.balanceOf', args: [ctx.wallet2.address], assertEql: 0, },

{ send: 'tokens.TST.mint', args: [ctx.contracts.TestERC20Faucet.address, et.eth(0.5)], },

{ send: 'TestERC20Faucet.setThreshold', args: [ctx.contracts.tokens.TST.address, et.eth(1)], },

{ from: ctx.wallet2, send: 'TestERC20Faucet.withdraw', args: [ctx.contracts.tokens.TST.address, ],
expectError: 'ERC20: transfer amount exceeds balance',
},

{ call: 'tokens.TST.balanceOf', args: [ctx.wallet2.address], assertEql: 0, },
],
})


.test({
desc: "withdraw reverts if user balance is not below threshold",
actions: ctx => [
{ send: 'tokens.TST.mint', args: [ctx.contracts.TestERC20Faucet.address, et.eth(0.5)], },

{ send: 'tokens.TST.mint', args: [ctx.wallet2.address, et.eth(0.5)], },

{ send: 'TestERC20Faucet.setThreshold', args: [ctx.contracts.tokens.TST.address, et.eth(0.5)], },

{ from: ctx.wallet2, send: 'TestERC20Faucet.withdraw', args: [ctx.contracts.tokens.TST.address, ],
expectError: 'withdraw: balance not below threshold',
},

{ call: 'tokens.TST.balanceOf', args: [ctx.wallet2.address], assertEql: et.eth(0.5), },
],
})


.test({
desc: "user can withdraw multiple tokkens",
actions: ctx => [
{ send: 'tokens.TST.mint', args: [ctx.contracts.TestERC20Faucet.address, et.eth(0.5)], },
{ send: 'tokens.TST2.mint', args: [ctx.contracts.TestERC20Faucet.address, et.eth(0.5)], },

{ send: 'TestERC20Faucet.setThreshold', args: [ctx.contracts.tokens.TST.address, et.eth(0.25)], },
{ send: 'TestERC20Faucet.setThreshold', args: [ctx.contracts.tokens.TST2.address, et.eth(0.2)], },

{ from: ctx.wallet2, send: 'TestERC20Faucet.withdraw', args: [ctx.contracts.tokens.TST.address, ], },
{ call: 'tokens.TST.balanceOf', args: [ctx.wallet2.address], assertEql: et.eth(0.25), },

{ from: ctx.wallet2, send: 'TestERC20Faucet.withdraw', args: [ctx.contracts.tokens.TST2.address, ], },
{ call: 'tokens.TST2.balanceOf', args: [ctx.wallet2.address], assertEql: et.eth(0.2), },

{ call: 'tokens.TST.balanceOf', args: [ctx.contracts.TestERC20Faucet.address], assertEql: et.eth(0.25), },
{ call: 'tokens.TST2.balanceOf', args: [ctx.contracts.TestERC20Faucet.address], assertEql: et.eth(0.3), },
],
})



.run();