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
|
@ -7,5 +7,6 @@ library StaticATokenErrors {
|
||||||
string public constant INVALID_SIGNATURE = '3';
|
string public constant INVALID_SIGNATURE = '3';
|
||||||
string public constant INVALID_DEPOSITOR = '4';
|
string public constant INVALID_DEPOSITOR = '4';
|
||||||
string public constant INVALID_RECIPIENT = '5';
|
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.
|
* @dev Claim rewards on behalf of a user and send them to a receiver
|
||||||
* @param receiver The address of the receiver of rewards
|
* @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`
|
* @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) {
|
if (forceUpdate) {
|
||||||
collectAndUpdateRewards();
|
collectAndUpdateRewards();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint256 balance = balanceOf(msg.sender);
|
uint256 balance = balanceOf(onBehalfOf);
|
||||||
uint256 reward = _getClaimableRewards(msg.sender, balance, false);
|
uint256 reward = _getClaimableRewards(onBehalfOf, balance, false);
|
||||||
uint256 totBal = REWARD_TOKEN.balanceOf(address(this));
|
uint256 totBal = REWARD_TOKEN.balanceOf(address(this));
|
||||||
if (reward > totBal) {
|
if (reward > totBal) {
|
||||||
// Throw away excess unclaimed rewards
|
|
||||||
reward = totBal;
|
reward = totBal;
|
||||||
}
|
}
|
||||||
if (reward > 0) {
|
if (reward > 0) {
|
||||||
_unclaimedRewards[msg.sender] = 0;
|
_unclaimedRewards[onBehalfOf] = 0;
|
||||||
_updateUserSnapshotRewardsPerToken(msg.sender);
|
_updateUserSnapshotRewardsPerToken(onBehalfOf);
|
||||||
REWARD_TOKEN.safeTransfer(receiver, reward);
|
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 {
|
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);
|
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 amountToDeposit = utils.parseEther('1.135359735917531199'); // 18 decimals should be the worst here //1.135359735917531199
|
||||||
const users = await DRE.ethers.getSigners();
|
const users = await DRE.ethers.getSigners();
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ import {
|
||||||
StaticAToken,
|
StaticAToken,
|
||||||
StaticATokenLM,
|
StaticATokenLM,
|
||||||
} from '../../../../types';
|
} from '../../../../types';
|
||||||
|
import { IAaveIncentivesControllerFactory } from '../../../../types/IAaveIncentivesControllerFactory';
|
||||||
import {
|
import {
|
||||||
impersonateAccountsHardhat,
|
impersonateAccountsHardhat,
|
||||||
DRE,
|
DRE,
|
||||||
|
@ -28,18 +29,16 @@ import { BigNumber, providers, Signer, utils } from 'ethers';
|
||||||
import { rayDiv, rayMul } from '../../../../helpers/ray-math';
|
import { rayDiv, rayMul } from '../../../../helpers/ray-math';
|
||||||
import { MAX_UINT_AMOUNT, ZERO_ADDRESS } from '../../../../helpers/constants';
|
import { MAX_UINT_AMOUNT, ZERO_ADDRESS } from '../../../../helpers/constants';
|
||||||
import { tEthereumAddress } from '../../../../helpers/types';
|
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 {
|
import {
|
||||||
buildMetaDepositParams,
|
buildMetaDepositParams,
|
||||||
buildMetaWithdrawParams,
|
buildMetaWithdrawParams,
|
||||||
buildPermitParams,
|
buildPermitParams,
|
||||||
getSignatureFromTypedData,
|
getSignatureFromTypedData,
|
||||||
} from '../../../../helpers/contracts-helpers';
|
} from '../../../../helpers/contracts-helpers';
|
||||||
import { TypedDataUtils, typedSignatureHash, TYPED_MESSAGE_SCHEMA } from 'eth-sig-util';
|
import { IAaveIncentivesController } from '../../../../types/IAaveIncentivesController';
|
||||||
import { zeroAddress } from 'ethereumjs-util';
|
import { deploySelfdestructTransferMock } from '../../../../helpers/contracts-deployments';
|
||||||
|
|
||||||
const { expect, use } = require('chai');
|
const { expect, use } = require('chai');
|
||||||
|
|
||||||
|
@ -56,11 +55,8 @@ const LENDING_POOL = '0x7d2768dE32b0b80b7a3454c06BdAc94A69DDc7A9';
|
||||||
const WETH = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2';
|
const WETH = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2';
|
||||||
const STKAAVE = '0x4da27a545c0c5B758a6BA100e3a049001de870f5';
|
const STKAAVE = '0x4da27a545c0c5B758a6BA100e3a049001de870f5';
|
||||||
const AWETH = '0x030bA81f1c18d280636F32af80b9AAd02Cf0854e';
|
const AWETH = '0x030bA81f1c18d280636F32af80b9AAd02Cf0854e';
|
||||||
|
const INCENTIVES_CONTROLLER = '0xd784927Ff2f95ba542BfC824c8a8a98F3495f6b5';
|
||||||
const TEST_USERS = [
|
const EMISSION_MANAGER = '0xEE56e2B3D491590B5b31738cC34d5232F378a8D5';
|
||||||
'0x0F4ee9631f4be0a63756515141281A3E2B293Bbe',
|
|
||||||
'0x8BffC896D42F07776561A5814D6E4240950d6D3a',
|
|
||||||
];
|
|
||||||
|
|
||||||
const LM_ERRORS = {
|
const LM_ERRORS = {
|
||||||
INVALID_OWNER: '1',
|
INVALID_OWNER: '1',
|
||||||
|
@ -68,7 +64,8 @@ const LM_ERRORS = {
|
||||||
INVALID_SIGNATURE: '3',
|
INVALID_SIGNATURE: '3',
|
||||||
INVALID_DEPOSITOR: '4',
|
INVALID_DEPOSITOR: '4',
|
||||||
INVALID_RECIPIENT: '5',
|
INVALID_RECIPIENT: '5',
|
||||||
ONLY_ONE_AMOUNT_FORMAT_ALLOWED: '6',
|
INVALID_CLAIMER: '6',
|
||||||
|
ONLY_ONE_AMOUNT_FORMAT_ALLOWED: '7',
|
||||||
};
|
};
|
||||||
|
|
||||||
type tBalancesInvolved = {
|
type tBalancesInvolved = {
|
||||||
|
@ -141,6 +138,7 @@ describe('StaticATokenLM: aToken wrapper with static balances and liquidity mini
|
||||||
let userSigner: providers.JsonRpcSigner;
|
let userSigner: providers.JsonRpcSigner;
|
||||||
let user2Signer: providers.JsonRpcSigner;
|
let user2Signer: providers.JsonRpcSigner;
|
||||||
let lendingPool: LendingPool;
|
let lendingPool: LendingPool;
|
||||||
|
let incentives: IAaveIncentivesController;
|
||||||
let weth: WETH9;
|
let weth: WETH9;
|
||||||
let aweth: AToken;
|
let aweth: AToken;
|
||||||
let stkAave: ERC20;
|
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());
|
userSigner = DRE.ethers.provider.getSigner(await user1.getAddress());
|
||||||
user2Signer = DRE.ethers.provider.getSigner(await user2.getAddress());
|
user2Signer = DRE.ethers.provider.getSigner(await user2.getAddress());
|
||||||
lendingPool = LendingPoolFactory.connect(LENDING_POOL, userSigner);
|
lendingPool = LendingPoolFactory.connect(LENDING_POOL, userSigner);
|
||||||
|
incentives = IAaveIncentivesControllerFactory.connect(INCENTIVES_CONTROLLER, userSigner);
|
||||||
|
|
||||||
weth = WETH9Factory.connect(WETH, userSigner);
|
weth = WETH9Factory.connect(WETH, userSigner);
|
||||||
aweth = ATokenFactory.connect(AWETH, 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);
|
const ctxtAfterWithdrawal = await getContext(ctxtParams);
|
||||||
|
|
||||||
expect(ctxtBeforeWithdrawal.userATokenBalance).to.be.eq(0);
|
expect(ctxtBeforeWithdrawal.userATokenBalance).to.be.eq(0);
|
||||||
expect(ctxtBeforeWithdrawal.staticATokenATokenBalance).to.be.eq(amountToDeposit);
|
expect(ctxtBeforeWithdrawal.staticATokenATokenBalance).to.be.closeTo(amountToDeposit, 2);
|
||||||
expect(ctxtAfterWithdrawal.userATokenBalance).to.be.eq(amountToWithdraw);
|
expect(ctxtAfterWithdrawal.userATokenBalance).to.be.closeTo(amountToWithdraw, 2);
|
||||||
expect(ctxtAfterWithdrawal.userDynamicStaticATokenBalance).to.be.eq(
|
expect(ctxtAfterWithdrawal.userDynamicStaticATokenBalance).to.be.closeTo(
|
||||||
BigNumber.from(
|
BigNumber.from(
|
||||||
rayMul(
|
rayMul(
|
||||||
new bnjs(ctxtBeforeWithdrawal.userStaticATokenBalance.toString()),
|
new bnjs(ctxtBeforeWithdrawal.userStaticATokenBalance.toString()),
|
||||||
new bnjs(ctxtAfterWithdrawal.currentRate.toString())
|
new bnjs(ctxtAfterWithdrawal.currentRate.toString())
|
||||||
).toString()
|
).toString()
|
||||||
).sub(amountToWithdraw)
|
).sub(amountToWithdraw),
|
||||||
|
2
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(ctxtAfterWithdrawal.userStkAaveBalance).to.be.eq(0);
|
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 dust to be left in the contract
|
||||||
expect(ctxtAfterClaim.staticATokenStkAaveBalance).to.be.lt(5);
|
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