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

TRUST QA-6/7: Optimizations in Distributor #988

Merged
merged 23 commits into from
Oct 24, 2023
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
3 changes: 3 additions & 0 deletions contracts/facade/FacadeTest.sol
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ contract FacadeTest is IFacadeTest {
erc20s
);
try main.rsrTrader().manageTokens(rsrERC20s, rsrKinds) {} catch {}
try main.rsrTrader().distributeTokenToBuy() {} catch {}

// Start exact RToken auctions
(IERC20[] memory rTokenERC20s, TradeKind[] memory rTokenKinds) = traderERC20s(
Expand All @@ -74,6 +75,7 @@ contract FacadeTest is IFacadeTest {
erc20s
);
try main.rTokenTrader().manageTokens(rTokenERC20s, rTokenKinds) {} catch {}
try main.rTokenTrader().distributeTokenToBuy() {} catch {}
// solhint-enable no-empty-blocks
}

Expand Down Expand Up @@ -133,6 +135,7 @@ contract FacadeTest is IFacadeTest {
IERC20[] memory traderERC20sAll = new IERC20[](erc20sAll.length);
for (uint256 i = 0; i < erc20sAll.length; ++i) {
if (
erc20sAll[i] != trader.tokenToBuy() &&
address(trader.trades(erc20sAll[i])) == address(0) &&
erc20sAll[i].balanceOf(address(trader)) > 1
) {
Expand Down
4 changes: 2 additions & 2 deletions contracts/p0/Distributor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ contract DistributorP0 is ComponentP0, IDistributor {
{
RevenueTotals memory revTotals = totals();
uint256 totalShares = isRSR ? revTotals.rsrTotal : revTotals.rTokenTotal;
require(totalShares > 0, "nothing to distribute");
tokensPerShare = amount / totalShares;
if (totalShares > 0) tokensPerShare = amount / totalShares;
require(tokensPerShare > 0, "nothing to distribute");
}

// Evenly distribute revenue tokens per distribution share.
Expand Down
13 changes: 4 additions & 9 deletions contracts/p1/Distributor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ contract DistributorP1 is ComponentP1, IDistributor {
}

struct Transfer {
IERC20 erc20;
address addrTo;
uint256 amount;
}
Expand Down Expand Up @@ -99,8 +98,8 @@ contract DistributorP1 is ComponentP1, IDistributor {
{
RevenueTotals memory revTotals = totals();
uint256 totalShares = isRSR ? revTotals.rsrTotal : revTotals.rTokenTotal;
require(totalShares > 0, "nothing to distribute");
tokensPerShare = amount / totalShares;
if (totalShares > 0) tokensPerShare = amount / totalShares;
require(tokensPerShare > 0, "nothing to distribute");
}

// Evenly distribute revenue tokens per distribution share.
Expand Down Expand Up @@ -131,19 +130,15 @@ contract DistributorP1 is ComponentP1, IDistributor {
if (transferAmt > 0) accountRewards = true;
}

transfers[numTransfers] = Transfer({
erc20: erc20,
addrTo: addrTo,
amount: transferAmt
});
transfers[numTransfers] = Transfer({ addrTo: addrTo, amount: transferAmt });
numTransfers++;
}
emit RevenueDistributed(erc20, caller, amount);

// == Interactions ==
for (uint256 i = 0; i < numTransfers; i++) {
Transfer memory t = transfers[i];
IERC20Upgradeable(address(t.erc20)).safeTransferFrom(caller, t.addrTo, t.amount);
IERC20Upgradeable(address(erc20)).safeTransferFrom(caller, t.addrTo, t.amount);
}

// Perform reward accounting
Expand Down
4 changes: 3 additions & 1 deletion contracts/plugins/mocks/RevenueTraderBackComp.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ contract RevenueTraderCompatibleV2 is RevenueTraderP1, IRevenueTraderComp {
erc20s[0] = sell;
TradeKind[] memory kinds = new TradeKind[](1);
kinds[0] = TradeKind.DUTCH_AUCTION;

// Mirror V3 logic (only the section relevant to tests)
this.manageTokens(erc20s, kinds);
// solhint-disable-next-line no-empty-blocks
try this.manageTokens(erc20s, kinds) {} catch {}
}

function version() public pure virtual override(Versioned, IVersioned) returns (string memory) {
Expand Down
11 changes: 11 additions & 0 deletions test/Revenues.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,17 @@ describe(`Revenues - P${IMPLEMENTATION}`, () => {
expect(newRTokenTotal).equal(bn(0))
})

it('Should avoid zero transfers when distributing tokenToBuy', async () => {
// Distribute with no balance
await expect(rsrTrader.distributeTokenToBuy()).to.be.revertedWith('nothing to distribute')
expect(await rsr.balanceOf(stRSR.address)).to.equal(bn(0))

// Small amount which ends in zero distribution due to rounding
await rsr.connect(owner).mint(rsrTrader.address, bn(1))
await expect(rsrTrader.distributeTokenToBuy()).to.be.revertedWith('nothing to distribute')
expect(await rsr.balanceOf(stRSR.address)).to.equal(bn(0))
})

it('Should account rewards when distributing tokenToBuy', async () => {
// 1. StRSR.payoutRewards()
const stRSRBal = await rsr.balanceOf(stRSR.address)
Expand Down