diff --git a/contracts/protocol/tokenization/base/ScaledBalanceTokenBase.sol b/contracts/protocol/tokenization/base/ScaledBalanceTokenBase.sol index 711fc9de8..033728e43 100644 --- a/contracts/protocol/tokenization/base/ScaledBalanceTokenBase.sol +++ b/contracts/protocol/tokenization/base/ScaledBalanceTokenBase.sol @@ -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); } diff --git a/test-suites/atoken-events.spec.ts b/test-suites/atoken-events.spec.ts index 6de8cf0cb..68939197f 100644 --- a/test-suites/atoken-events.spec.ts +++ b/test-suites/atoken-events.spec.ts @@ -20,6 +20,7 @@ import { withdraw, getATokenEvent, transferFrom, + printATokenEvents, } from './helpers/utils/tokenization-events'; const DEBUG = false; @@ -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; diff --git a/test-suites/helpers/utils/tokenization-events.ts b/test-suites/helpers/utils/tokenization-events.ts index d2be4cf3d..b1a72b295 100644 --- a/test-suites/helpers/utils/tokenization-events.ts +++ b/test-suites/helpers/utils/tokenization-events.ts @@ -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); @@ -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, @@ -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); @@ -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,