Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimizes logic of self transfers of aTokens #759

Merged
merged 1 commit into from
Dec 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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