mirror of
https://github.com/Instadapp/aave-protocol-v2.git
synced 2024-07-29 21:47:30 +00:00
feat: Add claimOnBehalf
function + tests
This commit is contained in:
parent
290ba077f5
commit
00e01d816e
contracts/protocol
test-suites/test-aave/mainnet/static-atoken-lm
|
@ -7,5 +7,6 @@ library StaticATokenErrors {
|
|||
string public constant INVALID_SIGNATURE = '3';
|
||||
string public constant INVALID_DEPOSITOR = '4';
|
||||
string public constant INVALID_RECIPIENT = '5';
|
||||
string public constant ONLY_ONE_AMOUNT_FORMAT_ALLOWED = '6';
|
||||
string public constant INVALID_CLAIMER = '6';
|
||||
string public constant ONLY_ONE_AMOUNT_FORMAT_ALLOWED = '7';
|
||||
}
|
||||
|
|
|
@ -491,31 +491,51 @@ contract StaticATokenLM is ERC20 {
|
|||
}
|
||||
|
||||
/**
|
||||
* @dev Claim rewards for a user and send them to a receiver.
|
||||
* @param receiver The address of the receiver of rewards
|
||||
* @dev Claim rewards on behalf of a user and send them to a receiver
|
||||
* @param onBehalfOf The address to claim on behalf of
|
||||
* @param receiver The address to receive the rewards
|
||||
* @param forceUpdate Flag to retrieve latest rewards from `INCENTIVES_CONTROLLER`
|
||||
*/
|
||||
function claimRewards(address receiver, bool forceUpdate) public {
|
||||
function _claimRewardsOnBehalf(
|
||||
address onBehalfOf,
|
||||
address receiver,
|
||||
bool forceUpdate
|
||||
) internal {
|
||||
if (forceUpdate) {
|
||||
collectAndUpdateRewards();
|
||||
}
|
||||
|
||||
uint256 balance = balanceOf(msg.sender);
|
||||
uint256 reward = _getClaimableRewards(msg.sender, balance, false);
|
||||
uint256 balance = balanceOf(onBehalfOf);
|
||||
uint256 reward = _getClaimableRewards(onBehalfOf, balance, false);
|
||||
uint256 totBal = REWARD_TOKEN.balanceOf(address(this));
|
||||
if (reward > totBal) {
|
||||
// Throw away excess unclaimed rewards
|
||||
reward = totBal;
|
||||
}
|
||||
if (reward > 0) {
|
||||
_unclaimedRewards[msg.sender] = 0;
|
||||
_updateUserSnapshotRewardsPerToken(msg.sender);
|
||||
_unclaimedRewards[onBehalfOf] = 0;
|
||||
_updateUserSnapshotRewardsPerToken(onBehalfOf);
|
||||
REWARD_TOKEN.safeTransfer(receiver, reward);
|
||||
}
|
||||
}
|
||||
|
||||
function claimRewardsOnBehalf(
|
||||
address onBehalfOf,
|
||||
address receiver,
|
||||
bool forceUpdate
|
||||
) external {
|
||||
require(
|
||||
msg.sender == onBehalfOf || msg.sender == INCENTIVES_CONTROLLER.getClaimer(onBehalfOf),
|
||||
StaticATokenErrors.INVALID_CLAIMER
|
||||
);
|
||||
_claimRewardsOnBehalf(onBehalfOf, receiver, forceUpdate);
|
||||
}
|
||||
|
||||
function claimRewards(address receiver, bool forceUpdate) external {
|
||||
_claimRewardsOnBehalf(msg.sender, receiver, forceUpdate);
|
||||
}
|
||||
|
||||
function claimRewardsToSelf(bool forceUpdate) external {
|
||||
claimRewards(msg.sender, forceUpdate);
|
||||
_claimRewardsOnBehalf(msg.sender, msg.sender, forceUpdate);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -895,7 +895,7 @@ describe('StaticATokenLM: aToken wrapper with static balances and liquidity mini
|
|||
expect(await stkAave.balanceOf(staticAToken.address)).to.be.lt(DUST);
|
||||
});
|
||||
|
||||
it('mass deposits, mass withdraws and mass claims', async () => {
|
||||
it('Mass deposits, mass withdraws and mass claims', async () => {
|
||||
const amountToDeposit = utils.parseEther('1.135359735917531199'); // 18 decimals should be the worst here //1.135359735917531199
|
||||
const users = await DRE.ethers.getSigners();
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ import {
|
|||
StaticAToken,
|
||||
StaticATokenLM,
|
||||
} from '../../../../types';
|
||||
import { IAaveIncentivesControllerFactory } from '../../../../types/IAaveIncentivesControllerFactory';
|
||||
import {
|
||||
impersonateAccountsHardhat,
|
||||
DRE,
|
||||
|
@ -28,18 +29,16 @@ import { BigNumber, providers, Signer, utils } from 'ethers';
|
|||
import { rayDiv, rayMul } from '../../../../helpers/ray-math';
|
||||
import { MAX_UINT_AMOUNT, ZERO_ADDRESS } from '../../../../helpers/constants';
|
||||
import { tEthereumAddress } from '../../../../helpers/types';
|
||||
import { AbiCoder, formatEther, verifyTypedData } from 'ethers/lib/utils';
|
||||
import { stat } from 'fs';
|
||||
|
||||
import { _TypedDataEncoder } from 'ethers/lib/utils';
|
||||
import { parseEther, _TypedDataEncoder } from 'ethers/lib/utils';
|
||||
import {
|
||||
buildMetaDepositParams,
|
||||
buildMetaWithdrawParams,
|
||||
buildPermitParams,
|
||||
getSignatureFromTypedData,
|
||||
} from '../../../../helpers/contracts-helpers';
|
||||
import { TypedDataUtils, typedSignatureHash, TYPED_MESSAGE_SCHEMA } from 'eth-sig-util';
|
||||
import { zeroAddress } from 'ethereumjs-util';
|
||||
import { IAaveIncentivesController } from '../../../../types/IAaveIncentivesController';
|
||||
import { deploySelfdestructTransferMock } from '../../../../helpers/contracts-deployments';
|
||||
|
||||
const { expect, use } = require('chai');
|
||||
|
||||
|
@ -56,11 +55,8 @@ const LENDING_POOL = '0x7d2768dE32b0b80b7a3454c06BdAc94A69DDc7A9';
|
|||
const WETH = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2';
|
||||
const STKAAVE = '0x4da27a545c0c5B758a6BA100e3a049001de870f5';
|
||||
const AWETH = '0x030bA81f1c18d280636F32af80b9AAd02Cf0854e';
|
||||
|
||||
const TEST_USERS = [
|
||||
'0x0F4ee9631f4be0a63756515141281A3E2B293Bbe',
|
||||
'0x8BffC896D42F07776561A5814D6E4240950d6D3a',
|
||||
];
|
||||
const INCENTIVES_CONTROLLER = '0xd784927Ff2f95ba542BfC824c8a8a98F3495f6b5';
|
||||
const EMISSION_MANAGER = '0xEE56e2B3D491590B5b31738cC34d5232F378a8D5';
|
||||
|
||||
const LM_ERRORS = {
|
||||
INVALID_OWNER: '1',
|
||||
|
@ -68,7 +64,8 @@ const LM_ERRORS = {
|
|||
INVALID_SIGNATURE: '3',
|
||||
INVALID_DEPOSITOR: '4',
|
||||
INVALID_RECIPIENT: '5',
|
||||
ONLY_ONE_AMOUNT_FORMAT_ALLOWED: '6',
|
||||
INVALID_CLAIMER: '6',
|
||||
ONLY_ONE_AMOUNT_FORMAT_ALLOWED: '7',
|
||||
};
|
||||
|
||||
type tBalancesInvolved = {
|
||||
|
@ -141,6 +138,7 @@ describe('StaticATokenLM: aToken wrapper with static balances and liquidity mini
|
|||
let userSigner: providers.JsonRpcSigner;
|
||||
let user2Signer: providers.JsonRpcSigner;
|
||||
let lendingPool: LendingPool;
|
||||
let incentives: IAaveIncentivesController;
|
||||
let weth: WETH9;
|
||||
let aweth: AToken;
|
||||
let stkAave: ERC20;
|
||||
|
@ -158,6 +156,7 @@ describe('StaticATokenLM: aToken wrapper with static balances and liquidity mini
|
|||
userSigner = DRE.ethers.provider.getSigner(await user1.getAddress());
|
||||
user2Signer = DRE.ethers.provider.getSigner(await user2.getAddress());
|
||||
lendingPool = LendingPoolFactory.connect(LENDING_POOL, userSigner);
|
||||
incentives = IAaveIncentivesControllerFactory.connect(INCENTIVES_CONTROLLER, userSigner);
|
||||
|
||||
weth = WETH9Factory.connect(WETH, userSigner);
|
||||
aweth = ATokenFactory.connect(AWETH, userSigner);
|
||||
|
@ -765,15 +764,16 @@ describe('StaticATokenLM: aToken wrapper with static balances and liquidity mini
|
|||
const ctxtAfterWithdrawal = await getContext(ctxtParams);
|
||||
|
||||
expect(ctxtBeforeWithdrawal.userATokenBalance).to.be.eq(0);
|
||||
expect(ctxtBeforeWithdrawal.staticATokenATokenBalance).to.be.eq(amountToDeposit);
|
||||
expect(ctxtAfterWithdrawal.userATokenBalance).to.be.eq(amountToWithdraw);
|
||||
expect(ctxtAfterWithdrawal.userDynamicStaticATokenBalance).to.be.eq(
|
||||
expect(ctxtBeforeWithdrawal.staticATokenATokenBalance).to.be.closeTo(amountToDeposit, 2);
|
||||
expect(ctxtAfterWithdrawal.userATokenBalance).to.be.closeTo(amountToWithdraw, 2);
|
||||
expect(ctxtAfterWithdrawal.userDynamicStaticATokenBalance).to.be.closeTo(
|
||||
BigNumber.from(
|
||||
rayMul(
|
||||
new bnjs(ctxtBeforeWithdrawal.userStaticATokenBalance.toString()),
|
||||
new bnjs(ctxtAfterWithdrawal.currentRate.toString())
|
||||
).toString()
|
||||
).sub(amountToWithdraw)
|
||||
).sub(amountToWithdraw),
|
||||
2
|
||||
);
|
||||
|
||||
expect(ctxtAfterWithdrawal.userStkAaveBalance).to.be.eq(0);
|
||||
|
@ -1047,4 +1047,270 @@ describe('StaticATokenLM: aToken wrapper with static balances and liquidity mini
|
|||
// Expect dust to be left in the contract
|
||||
expect(ctxtAfterClaim.staticATokenStkAaveBalance).to.be.lt(5);
|
||||
});
|
||||
|
||||
it('Deposit WETH on stataWETH, then transfer and withdraw of the whole balance in underlying, finally claimToSelf', async () => {
|
||||
const amountToDeposit = utils.parseEther('5');
|
||||
const amountToWithdraw = MAX_UINT_AMOUNT;
|
||||
|
||||
// Preparation
|
||||
await waitForTx(await weth.deposit({ value: amountToDeposit }));
|
||||
await waitForTx(await weth.approve(staticAToken.address, amountToDeposit, defaultTxParams));
|
||||
|
||||
const ctxtInitial = await getContext(ctxtParams);
|
||||
|
||||
// Deposit
|
||||
await waitForTx(
|
||||
await staticAToken.deposit(userSigner._address, amountToDeposit, 0, true, defaultTxParams)
|
||||
);
|
||||
|
||||
const ctxtAfterDeposit = await getContext(ctxtParams);
|
||||
// Transfer staticATokens to other user
|
||||
await waitForTx(
|
||||
await staticAToken.transfer(user2Signer._address, ctxtAfterDeposit.userStaticATokenBalance)
|
||||
);
|
||||
|
||||
const ctxtAfterTransfer = await getContext(ctxtParams);
|
||||
|
||||
// Withdraw
|
||||
await waitForTx(
|
||||
await staticAToken
|
||||
.connect(user2Signer)
|
||||
.withdraw(user2Signer._address, amountToWithdraw, true, defaultTxParams)
|
||||
);
|
||||
|
||||
const ctxtAfterWithdrawal = await getContext(ctxtParams);
|
||||
|
||||
// Claim
|
||||
await waitForTx(await staticAToken.connect(user2Signer).claimRewardsToSelf(true));
|
||||
const ctxtAfterClaim = await getContext(ctxtParams);
|
||||
|
||||
// Checks
|
||||
expect(ctxtAfterDeposit.staticATokenATokenBalance).to.be.eq(
|
||||
ctxtInitial.staticATokenATokenBalance.add(amountToDeposit)
|
||||
);
|
||||
expect(ctxtAfterDeposit.userUnderlyingBalance).to.be.eq(
|
||||
ctxtInitial.userUnderlyingBalance.sub(amountToDeposit)
|
||||
);
|
||||
expect(ctxtAfterTransfer.user2StaticATokenBalance).to.be.eq(
|
||||
ctxtAfterDeposit.userStaticATokenBalance
|
||||
);
|
||||
expect(ctxtAfterTransfer.userStaticATokenBalance).to.be.eq(0);
|
||||
expect(ctxtAfterTransfer.userPendingRewards).to.be.eq(0);
|
||||
expect(ctxtAfterTransfer.user2PendingRewards).to.be.gt(0);
|
||||
expect(ctxtAfterWithdrawal.staticATokenSupply).to.be.eq(0);
|
||||
expect(ctxtAfterWithdrawal.staticATokenATokenBalance).to.be.eq(0);
|
||||
expect(ctxtAfterWithdrawal.userPendingRewards).to.be.eq(0);
|
||||
expect(ctxtAfterWithdrawal.staticATokenTotalClaimableRewards).to.be.gte(
|
||||
ctxtAfterWithdrawal.user2PendingRewards
|
||||
);
|
||||
|
||||
expect(ctxtAfterClaim.userStkAaveBalance).to.be.eq(0);
|
||||
expect(ctxtAfterClaim.user2StkAaveBalance).to.be.eq(ctxtAfterWithdrawal.user2PendingRewards);
|
||||
expect(ctxtAfterClaim.staticATokenStkAaveBalance).to.be.eq(
|
||||
ctxtAfterWithdrawal.staticATokenTotalClaimableRewards.sub(
|
||||
ctxtAfterWithdrawal.user2PendingRewards
|
||||
)
|
||||
);
|
||||
// Expect dust to be left in the contract
|
||||
expect(ctxtAfterClaim.staticATokenStkAaveBalance).to.be.lt(5);
|
||||
});
|
||||
|
||||
it('Deposit WETH on stataWETH, then transfer and withdraw of the whole balance in underlying, finally someone claims on behalf', async () => {
|
||||
const amountToDeposit = utils.parseEther('5');
|
||||
const amountToWithdraw = MAX_UINT_AMOUNT;
|
||||
|
||||
const [, , claimer] = await DRE.ethers.getSigners();
|
||||
const claimerSigner = DRE.ethers.provider.getSigner(await claimer.getAddress());
|
||||
|
||||
await impersonateAccountsHardhat([EMISSION_MANAGER]);
|
||||
const emissionManager = DRE.ethers.provider.getSigner(EMISSION_MANAGER);
|
||||
|
||||
// Fund emissionManager
|
||||
const selfdestructContract = await deploySelfdestructTransferMock();
|
||||
// Selfdestruct the mock, pointing to WETHGateway address
|
||||
await selfdestructContract
|
||||
.connect(user2Signer)
|
||||
.destroyAndTransfer(emissionManager._address, { value: parseEther('1') });
|
||||
|
||||
// Preparation
|
||||
await waitForTx(await weth.deposit({ value: amountToDeposit }));
|
||||
await waitForTx(await weth.approve(staticAToken.address, amountToDeposit, defaultTxParams));
|
||||
|
||||
const ctxtInitial = await getContext(ctxtParams);
|
||||
|
||||
// Allow another use to claim on behalf of
|
||||
await waitForTx(
|
||||
await incentives
|
||||
.connect(emissionManager)
|
||||
.setClaimer(user2Signer._address, claimerSigner._address)
|
||||
);
|
||||
|
||||
// Deposit
|
||||
await waitForTx(
|
||||
await staticAToken.deposit(userSigner._address, amountToDeposit, 0, true, defaultTxParams)
|
||||
);
|
||||
|
||||
const ctxtAfterDeposit = await getContext(ctxtParams);
|
||||
// Transfer staticATokens to other user
|
||||
await waitForTx(
|
||||
await staticAToken.transfer(user2Signer._address, ctxtAfterDeposit.userStaticATokenBalance)
|
||||
);
|
||||
|
||||
const ctxtAfterTransfer = await getContext(ctxtParams);
|
||||
|
||||
// Withdraw
|
||||
await waitForTx(
|
||||
await staticAToken
|
||||
.connect(user2Signer)
|
||||
.withdraw(user2Signer._address, amountToWithdraw, true, defaultTxParams)
|
||||
);
|
||||
|
||||
const ctxtAfterWithdrawal = await getContext(ctxtParams);
|
||||
|
||||
// Claim
|
||||
await waitForTx(
|
||||
await staticAToken
|
||||
.connect(claimerSigner)
|
||||
.claimRewardsOnBehalf(user2Signer._address, user2Signer._address, true)
|
||||
);
|
||||
const ctxtAfterClaim = await getContext(ctxtParams);
|
||||
|
||||
// Checks
|
||||
expect(ctxtAfterDeposit.staticATokenATokenBalance).to.be.eq(
|
||||
ctxtInitial.staticATokenATokenBalance.add(amountToDeposit)
|
||||
);
|
||||
expect(ctxtAfterDeposit.userUnderlyingBalance).to.be.eq(
|
||||
ctxtInitial.userUnderlyingBalance.sub(amountToDeposit)
|
||||
);
|
||||
expect(ctxtAfterTransfer.user2StaticATokenBalance).to.be.eq(
|
||||
ctxtAfterDeposit.userStaticATokenBalance
|
||||
);
|
||||
expect(ctxtAfterTransfer.userStaticATokenBalance).to.be.eq(0);
|
||||
expect(ctxtAfterTransfer.userPendingRewards).to.be.eq(0);
|
||||
expect(ctxtAfterTransfer.user2PendingRewards).to.be.gt(0);
|
||||
expect(ctxtAfterWithdrawal.staticATokenSupply).to.be.eq(0);
|
||||
expect(ctxtAfterWithdrawal.staticATokenATokenBalance).to.be.eq(0);
|
||||
expect(ctxtAfterWithdrawal.userPendingRewards).to.be.eq(0);
|
||||
expect(ctxtAfterWithdrawal.staticATokenTotalClaimableRewards).to.be.gte(
|
||||
ctxtAfterWithdrawal.user2PendingRewards
|
||||
);
|
||||
|
||||
expect(ctxtAfterClaim.userStkAaveBalance).to.be.eq(0);
|
||||
expect(ctxtAfterClaim.user2StkAaveBalance).to.be.eq(ctxtAfterWithdrawal.user2PendingRewards);
|
||||
expect(ctxtAfterClaim.staticATokenStkAaveBalance).to.be.eq(
|
||||
ctxtAfterWithdrawal.staticATokenTotalClaimableRewards.sub(
|
||||
ctxtAfterWithdrawal.user2PendingRewards
|
||||
)
|
||||
);
|
||||
// Expect dust to be left in the contract
|
||||
expect(ctxtAfterClaim.staticATokenStkAaveBalance).to.be.lt(5);
|
||||
});
|
||||
|
||||
it('Deposit WETH on stataWETH, then transfer and withdraw of the whole balance in underlying, finally someone NOT set as claimer claims on behalf (reverts)', async () => {
|
||||
const amountToDeposit = utils.parseEther('5');
|
||||
const amountToWithdraw = MAX_UINT_AMOUNT;
|
||||
|
||||
const [, , claimer] = await DRE.ethers.getSigners();
|
||||
const claimerSigner = DRE.ethers.provider.getSigner(await claimer.getAddress());
|
||||
|
||||
// Preparation
|
||||
await waitForTx(await weth.deposit({ value: amountToDeposit }));
|
||||
await waitForTx(await weth.approve(staticAToken.address, amountToDeposit, defaultTxParams));
|
||||
|
||||
// Deposit
|
||||
await waitForTx(
|
||||
await staticAToken.deposit(userSigner._address, amountToDeposit, 0, true, defaultTxParams)
|
||||
);
|
||||
|
||||
const ctxtAfterDeposit = await getContext(ctxtParams);
|
||||
// Transfer staticATokens to other user
|
||||
await waitForTx(
|
||||
await staticAToken.transfer(user2Signer._address, ctxtAfterDeposit.userStaticATokenBalance)
|
||||
);
|
||||
|
||||
// Withdraw
|
||||
await waitForTx(
|
||||
await staticAToken
|
||||
.connect(user2Signer)
|
||||
.withdraw(user2Signer._address, amountToWithdraw, true, defaultTxParams)
|
||||
);
|
||||
|
||||
// Claim
|
||||
await expect(
|
||||
staticAToken
|
||||
.connect(claimerSigner)
|
||||
.claimRewardsOnBehalf(user2Signer._address, user2Signer._address, true)
|
||||
).to.be.revertedWith(LM_ERRORS.INVALID_CLAIMER);
|
||||
});
|
||||
|
||||
it('Deposit WETH on stataWETH, then transfer and withdraw of the whole balance in underlying, finally claims on behalf of self', async () => {
|
||||
const amountToDeposit = utils.parseEther('5');
|
||||
const amountToWithdraw = MAX_UINT_AMOUNT;
|
||||
|
||||
// Preparation
|
||||
await waitForTx(await weth.deposit({ value: amountToDeposit }));
|
||||
await waitForTx(await weth.approve(staticAToken.address, amountToDeposit, defaultTxParams));
|
||||
|
||||
const ctxtInitial = await getContext(ctxtParams);
|
||||
|
||||
// Deposit
|
||||
await waitForTx(
|
||||
await staticAToken.deposit(userSigner._address, amountToDeposit, 0, true, defaultTxParams)
|
||||
);
|
||||
|
||||
const ctxtAfterDeposit = await getContext(ctxtParams);
|
||||
// Transfer staticATokens to other user
|
||||
await waitForTx(
|
||||
await staticAToken.transfer(user2Signer._address, ctxtAfterDeposit.userStaticATokenBalance)
|
||||
);
|
||||
|
||||
const ctxtAfterTransfer = await getContext(ctxtParams);
|
||||
|
||||
// Withdraw
|
||||
await waitForTx(
|
||||
await staticAToken
|
||||
.connect(user2Signer)
|
||||
.withdraw(user2Signer._address, amountToWithdraw, true, defaultTxParams)
|
||||
);
|
||||
|
||||
const ctxtAfterWithdrawal = await getContext(ctxtParams);
|
||||
|
||||
// Claim
|
||||
await waitForTx(
|
||||
await staticAToken
|
||||
.connect(user2Signer)
|
||||
.claimRewardsOnBehalf(user2Signer._address, user2Signer._address, true)
|
||||
);
|
||||
const ctxtAfterClaim = await getContext(ctxtParams);
|
||||
|
||||
// Checks
|
||||
expect(ctxtAfterDeposit.staticATokenATokenBalance).to.be.eq(
|
||||
ctxtInitial.staticATokenATokenBalance.add(amountToDeposit)
|
||||
);
|
||||
expect(ctxtAfterDeposit.userUnderlyingBalance).to.be.eq(
|
||||
ctxtInitial.userUnderlyingBalance.sub(amountToDeposit)
|
||||
);
|
||||
expect(ctxtAfterTransfer.user2StaticATokenBalance).to.be.eq(
|
||||
ctxtAfterDeposit.userStaticATokenBalance
|
||||
);
|
||||
expect(ctxtAfterTransfer.userStaticATokenBalance).to.be.eq(0);
|
||||
expect(ctxtAfterTransfer.userPendingRewards).to.be.eq(0);
|
||||
expect(ctxtAfterTransfer.user2PendingRewards).to.be.gt(0);
|
||||
expect(ctxtAfterWithdrawal.staticATokenSupply).to.be.eq(0);
|
||||
expect(ctxtAfterWithdrawal.staticATokenATokenBalance).to.be.eq(0);
|
||||
expect(ctxtAfterWithdrawal.userPendingRewards).to.be.eq(0);
|
||||
expect(ctxtAfterWithdrawal.staticATokenTotalClaimableRewards).to.be.gte(
|
||||
ctxtAfterWithdrawal.user2PendingRewards
|
||||
);
|
||||
|
||||
expect(ctxtAfterClaim.userStkAaveBalance).to.be.eq(0);
|
||||
expect(ctxtAfterClaim.user2StkAaveBalance).to.be.eq(ctxtAfterWithdrawal.user2PendingRewards);
|
||||
expect(ctxtAfterClaim.staticATokenStkAaveBalance).to.be.eq(
|
||||
ctxtAfterWithdrawal.staticATokenTotalClaimableRewards.sub(
|
||||
ctxtAfterWithdrawal.user2PendingRewards
|
||||
)
|
||||
);
|
||||
// Expect dust to be left in the contract
|
||||
expect(ctxtAfterClaim.staticATokenStkAaveBalance).to.be.lt(5);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue
Block a user