Skip to content

Commit

Permalink
Merge pull request #759 from aave/fix/757-self-transfer-improve
Browse files Browse the repository at this point in the history
Optimizes logic of self transfers of aTokens
  • Loading branch information
miguelmtzinf authored Dec 7, 2022
2 parents d7d9e30 + 6c3154e commit 4449676
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ abstract contract ScaledBalanceTokenBase is MintableIncentivizedERC20, IScaledBa
emit Mint(_msgSender(), sender, senderBalanceIncrease, senderBalanceIncrease, index);
}

if (recipientBalanceIncrease > 0) {
if (sender != recipient && recipientBalanceIncrease > 0) {
emit Transfer(address(0), recipient, recipientBalanceIncrease);
emit Mint(_msgSender(), recipient, recipientBalanceIncrease, recipientBalanceIncrease, index);
}
Expand Down
106 changes: 106 additions & 0 deletions test-suites/atoken-events.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
withdraw,
getATokenEvent,
transferFrom,
printATokenEvents,
} from './helpers/utils/tokenization-events';

const DEBUG = false;
Expand Down Expand Up @@ -403,6 +404,111 @@ makeSuite('AToken: Events', (testEnv: TestEnv) => {
expect(bobBalanceAfter).to.be.closeTo(bobBalanceBefore.add(balances.balance[bob.address]), 2);
};

it('Alice supplies 1000, transfers 100 to Bob, transfers 500 to itself, Bob transfers 500 from Alice to itself, withdraws 400 to Bob (without index change)', async () => {
await testMultipleTransfersAndWithdrawals(false);
});

it('Alice supplies 1000, transfers 100 to Bob, transfers 500 to itself, Bob transfers 500 from Alice to itself, withdraws 400 to Bob (with index change)', async () => {
await testMultipleTransfersAndWithdrawals(true);
});

const testMultipleTransfersAndWithdrawals = async (indexChange: boolean) => {
const { pool, dai, aDai, weth } = testEnv;

let rcpt;
let balanceTransferEv;
let aliceBalanceBefore = await aDai.balanceOf(alice.address);
let bobBalanceBefore = await aDai.balanceOf(bob.address);

log('- Alice supplies 1000 DAI');
rcpt = await supply(pool, alice, dai.address, '1000', alice.address, DEBUG);
updateBalances(balances, aDai, rcpt);

if (indexChange) {
log('- Increase index due to great borrow of DAI');
await increaseSupplyIndex(pool, borrower, weth.address, dai.address);
}

log('- Alice transfers 100 DAI to Bob');
let [fromScaledBefore, toScaledBefore] = await Promise.all([
aDai.scaledBalanceOf(alice.address),
aDai.scaledBalanceOf(bob.address),
]);
rcpt = await transfer(pool, alice, dai.address, '100', bob.address, DEBUG);
updateBalances(balances, aDai, rcpt);
balanceTransferEv = getATokenEvent(aDai, rcpt, 'BalanceTransfer')[0];
expect(await aDai.scaledBalanceOf(alice.address)).to.be.eq(
fromScaledBefore.sub(balanceTransferEv.value),
'Scaled balance emitted in BalanceTransfer event does not match'
);
expect(await aDai.scaledBalanceOf(bob.address)).to.be.eq(
toScaledBefore.add(balanceTransferEv.value),
'Scaled balance emitted in BalanceTransfer event does not match'
);

if (indexChange) {
log('- Increase index due to great borrow of DAI');
await increaseSupplyIndex(pool, borrower, weth.address, dai.address);
}

log('- Alice transfers 500 DAI to itself');
fromScaledBefore = await aDai.scaledBalanceOf(alice.address);
rcpt = await transfer(pool, alice, dai.address, '500', alice.address, DEBUG);
updateBalances(balances, aDai, rcpt);
expect(await aDai.scaledBalanceOf(alice.address)).to.be.eq(
fromScaledBefore,
'Scaled balance should remain the same'
);

if (indexChange) {
log('- Increase index due to great borrow of DAI');
await increaseSupplyIndex(pool, borrower, weth.address, dai.address);
}

log('- Bob transfersFrom Alice 500 DAI to Alice');
fromScaledBefore = await aDai.scaledBalanceOf(alice.address);
expect(
await aDai
.connect(alice.signer)
.approve(bob.address, await convertToCurrencyDecimals(dai.address, '500'))
);
rcpt = await transferFrom(pool, bob, alice.address, dai.address, '500', alice.address, DEBUG);
updateBalances(balances, aDai, rcpt);
expect(await aDai.scaledBalanceOf(alice.address)).to.be.eq(
fromScaledBefore,
'Scaled balance should remain the same'
);

if (indexChange) {
log('- Increase index due to great borrow of DAI');
await increaseSupplyIndex(pool, borrower, weth.address, dai.address);
}

log('- Alice withdraws 400 DAI to Bob');
rcpt = await withdraw(pool, alice, dai.address, '200', bob.address, DEBUG);
updateBalances(balances, aDai, rcpt);

if (DEBUG) {
await printBalance('alice', aDai, alice.address);
await printBalance('bob', aDai, bob.address);
}

// Check final balances
rcpt = await supply(pool, alice, dai.address, '1', alice.address, false);
updateBalances(balances, aDai, rcpt);
const aliceBalanceAfter = await aDai.balanceOf(alice.address);

rcpt = await supply(pool, bob, dai.address, '1', bob.address, false);
updateBalances(balances, aDai, rcpt);
const bobBalanceAfter = await aDai.balanceOf(bob.address);

expect(aliceBalanceAfter).to.be.closeTo(
aliceBalanceBefore.add(balances.balance[alice.address]),
2
);
expect(bobBalanceAfter).to.be.closeTo(bobBalanceBefore.add(balances.balance[bob.address]), 2);
};

it('Alice supplies 300000, withdraws 200000 to Bob, withdraws 5 to Bob', async () => {
const { pool, dai, aDai, weth } = testEnv;

Expand Down
18 changes: 12 additions & 6 deletions test-suites/helpers/utils/tokenization-events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,11 @@ export const transfer = async (

const indexAfter = await pool.getReserveNormalizedIncome(underlying);
const addedScaledBalance = amount.rayDiv(indexAfter);
const fromScaledBalance = (await aToken.scaledBalanceOf(user.address)).add(addedScaledBalance);
const toScaledBalance = (await aToken.scaledBalanceOf(to)).sub(addedScaledBalance);

// The amount of scaled balance transferred is 0 if self-transfer
const deltaScaledBalance = user.address == to ? BigNumber.from(0) : addedScaledBalance;
const fromScaledBalance = (await aToken.scaledBalanceOf(user.address)).add(deltaScaledBalance);
const toScaledBalance = (await aToken.scaledBalanceOf(to)).sub(deltaScaledBalance);
const fromBalanceIncrease = getBalanceIncrease(fromScaledBalance, fromPreviousIndex, indexAfter);
const toBalanceIncrease = getBalanceIncrease(toScaledBalance, toPreviousIndex, indexAfter);

Expand All @@ -230,7 +233,7 @@ export const transfer = async (
indexAfter,
]);
}
if (toBalanceIncrease.gt(0)) {
if (user.address != to && toBalanceIncrease.gt(0)) {
matchEvent(rcpt, 'Transfer', aToken, aToken.address, [ZERO_ADDRESS, to, toBalanceIncrease]);
matchEvent(rcpt, 'Mint', aToken, aToken.address, [
user.address,
Expand Down Expand Up @@ -265,8 +268,11 @@ export const transferFrom = async (

const indexAfter = await pool.getReserveNormalizedIncome(underlying);
const addedScaledBalance = amount.rayDiv(indexAfter);
const fromScaledBalance = (await aToken.scaledBalanceOf(origin)).add(addedScaledBalance);
const toScaledBalance = (await aToken.scaledBalanceOf(to)).sub(addedScaledBalance);

// The amount of scaled balance transferred is 0 if self-transfer
const deltaScaledBalance = origin == to ? BigNumber.from(0) : addedScaledBalance;
const fromScaledBalance = (await aToken.scaledBalanceOf(origin)).add(deltaScaledBalance);
const toScaledBalance = (await aToken.scaledBalanceOf(to)).sub(deltaScaledBalance);
const fromBalanceIncrease = getBalanceIncrease(fromScaledBalance, fromPreviousIndex, indexAfter);
const toBalanceIncrease = getBalanceIncrease(toScaledBalance, toPreviousIndex, indexAfter);

Expand All @@ -293,7 +299,7 @@ export const transferFrom = async (
indexAfter,
]);
}
if (toBalanceIncrease.gt(0)) {
if (origin != to && toBalanceIncrease.gt(0)) {
matchEvent(rcpt, 'Transfer', aToken, aToken.address, [ZERO_ADDRESS, to, toBalanceIncrease]);
matchEvent(rcpt, 'Mint', aToken, aToken.address, [
user.address,
Expand Down

0 comments on commit 4449676

Please sign in to comment.