Skip to content

Commit

Permalink
test: add mock test for ChargeFee
Browse files Browse the repository at this point in the history
  • Loading branch information
robercano committed Aug 18, 2023
1 parent c9c505b commit ce4747b
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
"outputs": [
{
"internalType": "int256",
"name": "price",
"name": "latestAnswer",
"type": "int256"
},
{
Expand Down
14 changes: 9 additions & 5 deletions packages/dma-contracts/contracts/actions/common/ChargeFee.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ import "../../core/types/Common.sol";

import { PercentageUtils } from "../../libs/PercentageUtils.sol";
import { PriceUtils } from "../../libs/PriceUtils.sol";

import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import { IOracleAdapter } from "../../interfaces/common/IOracleAdapter.sol";
import { USD } from "../../interfaces/common/IOracleAdapter.sol";

import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import { Address } from "@openzeppelin/contracts/utils/Address.sol";

/**
* @title ChargeFee Action contract
* @notice Action used to charge the AUM fee for a position. It will validate the data passed from the executor that
Expand All @@ -24,6 +25,7 @@ import { USD } from "../../interfaces/common/IOracleAdapter.sol";
contract ChargeFee is Executable, UseStore {
using ECDSA for bytes32;
using PercentageUtils for uint256;
using Address for address payable;

error InvalidSigner(address expectedSigner, address recoveredSigner);

Expand Down Expand Up @@ -53,7 +55,7 @@ contract ChargeFee is Executable, UseStore {
function _verifySignature(ChargeFeeData memory chargeFeeData) internal view {
address expectedBackendSigner = registry.getRegisteredService(BACKEND_MSG_SIGNER);
address recoveredBackendSigner = keccak256(
abi.encode(
abi.encodePacked(
chargeFeeData.feeAmount,
chargeFeeData.maxFeePercentage,
chargeFeeData.collateralAmount,
Expand Down Expand Up @@ -105,8 +107,9 @@ contract ChargeFee is Executable, UseStore {
function _calculateFeeAmount(
ChargeFeeData memory chargeFeeData,
uint256 netWorthInCollateral
) internal pure returns (uint256) {
) internal view returns (uint256) {
uint256 maxFeeAmount = netWorthInCollateral.applyPercentage(chargeFeeData.maxFeePercentage);

if (chargeFeeData.feeAmount > maxFeeAmount) {
return maxFeeAmount;
}
Expand All @@ -119,6 +122,7 @@ contract ChargeFee is Executable, UseStore {
address payable feeRecipient = payable(
registry.getRegisteredService("FeeRecipientJustForTest")
);
feeRecipient.call{ value: feeAmount }("");

feeRecipient.sendValue(feeAmount);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ interface IOracleAdapter {
function getLatestPrice(
address token,
address baseToken
) external view returns (int256 price, uint8 decimals);
) external view returns (int256 latestAnswer, uint8 decimals);

/// ERRORS
error OracleNotFound(address token, address baseToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { createDeploy } from '@dma-common/utils/deploy'
import init from '@dma-common/utils/init'
import { calldataTypes } from '@dma-library'
import { toSolidityPercentage } from '@dma-library/utils/percentages/percentage-utils'
import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'
import { BigNumber, utils } from 'ethers'
import { ethers } from 'hardhat'

Expand All @@ -14,9 +15,8 @@ import {
IServiceRegistry,
IServiceRegistry__factory,
} from '../../../../typechain'
import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'

describe.only('ChargeFee Action | Unit', () => {
describe('ChargeFee Action | Unit', () => {
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
const USD_ADDRESS = ZERO_ADDRESS
const BACKEND_MSG_SIGNER = 'BackendMsgSigner'
Expand All @@ -28,10 +28,10 @@ describe.only('ChargeFee Action | Unit', () => {
const DEBT_ASSET_PRICE = BigNumber.from('200000000')
const ORACLE_ADAPTER = 'OracleAdapter'
const FEE_RECIPIENT_JUST_FOR_TEST = 'FeeRecipientJustForTest'
const FEE_RECIPIENT_JUST_FOR_TEST_ADDRESS = '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599'

let backendSigner: SignerWithAddress
let backendSignerAddress: string
let feeRecipientAddress: string
let chargeFee: ChargeFee
let serviceRegistry: FakeContract<IServiceRegistry>
let oracleAdapter: FakeContract<IOracleAdapter>
Expand Down Expand Up @@ -89,6 +89,7 @@ describe.only('ChargeFee Action | Unit', () => {
// BACKEND SIGNER
backendSigner = (await ethers.getSigners())[0]
backendSignerAddress = await backendSigner.getAddress()
feeRecipientAddress = await (await ethers.getSigners())[1].getAddress()

// REGISTRY
serviceRegistry = await smock.fake<IServiceRegistry>(IServiceRegistry__factory.abi)
Expand All @@ -97,39 +98,71 @@ describe.only('ChargeFee Action | Unit', () => {
.returns(backendSignerAddress)
serviceRegistry.getRegisteredService
.whenCalledWith(FEE_RECIPIENT_JUST_FOR_TEST)
.returns(FEE_RECIPIENT_JUST_FOR_TEST_ADDRESS)
.returns(feeRecipientAddress)

// ORACLES
oracleAdapter = await smock.fake<IOracleAdapter>(IOracleAdapter__factory.abi)
oracleAdapter.getLatestPrice.whenCalledWith(COLLATERAL_ASSET_ADDRESS, USD_ADDRESS).returns({
latestAnswer: COLLATERAL_ASSET_PRICE,
decimals: COLLATERAL_ASSET_DECIMALS,
decimals: BigNumber.from(COLLATERAL_ASSET_DECIMALS),
})
oracleAdapter.getLatestPrice.whenCalledWith(DEBT_ASSET_ADDRESS, USD_ADDRESS).returns({
latestAnswer: DEBT_ASSET_PRICE,
decimals: DEBT_ASSET_DECIMALS,
decimals: BigNumber.from(DEBT_ASSET_DECIMALS),
})

serviceRegistry.getRegisteredService
.whenCalledWith(ORACLE_ADAPTER)
.returns(oracleAdapter.address)

// CHARGE FEE ACTION
const [deployedChargeFee] = await deploy('ChargeFee', [serviceRegistry.address])
chargeFee = deployedChargeFee as ChargeFee
})

it('should send correct fee to recipient', async () => {
it('should charge less than suggested fee', async () => {
const chargeFeeCalldata = await getChargeFeeCalldata(
BigNumber.from('1000000000000000000'),
toSolidityPercentage(1.0),
BigNumber.from('100000000000000000000'),
COLLATERAL_ASSET_ADDRESS,
COLLATERAL_ASSET_DECIMALS,
BigNumber.from('20000000000000000000'),
BigNumber.from('2000000000'),
DEBT_ASSET_ADDRESS,
DEBT_ASSET_DECIMALS,
)

await chargeFee.execute(chargeFeeCalldata, [])
const feeRecipientBalanceBefore = await ethers.provider.getBalance(feeRecipientAddress)

await chargeFee.execute(chargeFeeCalldata, [], { value: ethers.utils.parseEther('10') })

const feeRecipientBalanceAfter = await ethers.provider.getBalance(feeRecipientAddress)

expect(feeRecipientBalanceAfter.sub(feeRecipientBalanceBefore)).to.be.equal(
BigNumber.from('999781897491821155'),
)
})

it('should charge the suggested fee', async () => {
const chargeFeeCalldata = await getChargeFeeCalldata(
BigNumber.from('800000000000000000'),
toSolidityPercentage(1.0),
BigNumber.from('100000000000000000000'),
COLLATERAL_ASSET_ADDRESS,
COLLATERAL_ASSET_DECIMALS,
BigNumber.from('2000000000'),
DEBT_ASSET_ADDRESS,
DEBT_ASSET_DECIMALS,
)

const feeRecipientBalanceBefore = await ethers.provider.getBalance(feeRecipientAddress)

await chargeFee.execute(chargeFeeCalldata, [], { value: ethers.utils.parseEther('10') })

const feeRecipientBalanceAfter = await ethers.provider.getBalance(feeRecipientAddress)

expect(feeRecipientBalanceAfter.sub(feeRecipientBalanceBefore)).to.be.equal(
BigNumber.from('800000000000000000'),
)
})
})

0 comments on commit ce4747b

Please sign in to comment.