Skip to content

Commit d205660

Browse files
brandonilesBrandon Iles
andauthored
disallow rebase calls from contracts (#145)
Co-authored-by: Brandon Iles <brandon@ampleforth.org>
1 parent 394792f commit d205660

File tree

3 files changed

+53
-3
lines changed

3 files changed

+53
-3
lines changed

contracts/UFragmentsPolicy.sol

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,16 @@ contract UFragmentsPolicy is Ownable {
8383
uint256 private constant MAX_SUPPLY = ~(uint256(1) << 255) / MAX_RATE;
8484

8585
/**
86-
* @notice Anyone can call this function to initiate a new rebase operation, provided more than
87-
* the minimum time period has elapsed.
86+
* @notice Any EOA address can call this function to initiate a new rebase operation, provided
87+
* more than the minimum time period has elapsed.
88+
* Contracts are guarded from calling, to avoid flash loan attacks on liquidity
89+
* providers.
8890
* @dev The supply adjustment equals (_totalSupply * DeviationFromTargetRate) / rebaseLag
8991
* Where DeviationFromTargetRate is (MarketOracleRate - targetRate) / targetRate
9092
* and targetRate is CpiOracleRate / baseCpi
9193
*/
9294
function rebase() external {
95+
require(msg.sender == tx.origin); // solhint-disable-line avoid-tx-origin
9396
require(inRebaseWindow());
9497

9598
// This comparison also ensures there is no reentrancy.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
pragma solidity 0.4.24;
2+
3+
import "../UFragmentsPolicy.sol";
4+
5+
6+
contract RebaseCallerContract {
7+
UFragmentsPolicy private _policy;
8+
9+
constructor(address policy) public {
10+
_policy = UFragmentsPolicy(policy);
11+
}
12+
13+
function callRebase() public returns (bool) {
14+
// Take out a flash loan.
15+
// Do something funky...
16+
_policy.rebase(); // should fail
17+
// pay back flash loan.
18+
19+
return true;
20+
}
21+
}

test/unit/UFragmentsPolicy.js

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const UFragmentsPolicy = artifacts.require('UFragmentsPolicy.sol');
22
const MockUFragments = artifacts.require('MockUFragments.sol');
33
const MockOracle = artifacts.require('MockOracle.sol');
4+
const RebaseCallerContract = artifacts.require('RebaseCallerContract.sol');
45

56
const encodeCall = require('zos-lib/lib/helpers/encodeCall').default;
67
const BigNumber = web3.BigNumber;
@@ -12,7 +13,7 @@ require('chai')
1213
.use(require('chai-bignumber')(BigNumber))
1314
.should();
1415

15-
let uFragmentsPolicy, mockUFragments, mockMarketOracle, mockCpiOracle;
16+
let uFragmentsPolicy, mockUFragments, mockMarketOracle, mockCpiOracle, rebaseCallerContract;
1617
let r, prevEpoch, prevTime;
1718
let deployer, user;
1819

@@ -45,6 +46,7 @@ async function setupContracts () {
4546
});
4647
await uFragmentsPolicy.setMarketOracle(mockMarketOracle.address);
4748
await uFragmentsPolicy.setCpiOracle(mockCpiOracle.address);
49+
rebaseCallerContract = await RebaseCallerContract.new(uFragmentsPolicy.address);
4850
}
4951

5052
async function setupContractsWithOpenRebaseWindow () {
@@ -268,6 +270,30 @@ contract('UFragments:setRebaseTimingParameters:accessControl', function (account
268270
});
269271
});
270272

273+
contract('UFragmentsPolicy:Rebase:accessControl', async function (accounts) {
274+
before('setup UFragmentsPolicy contract', async function () {
275+
await setupContractsWithOpenRebaseWindow();
276+
await mockExternalData(INITIAL_RATE_30P_MORE, INITIAL_CPI, 1000, true);
277+
await chain.waitForSomeTime(60);
278+
});
279+
280+
describe('when rebase called by an EOA', function () {
281+
it('should succeed', async function () {
282+
expect(
283+
await chain.isEthException(uFragmentsPolicy.rebase())
284+
).to.be.false;
285+
});
286+
});
287+
288+
describe('when rebase called by a contract', function () {
289+
it('should fail', async function () {
290+
expect(
291+
await chain.isEthException(rebaseCallerContract.callRebase())
292+
).to.be.true;
293+
});
294+
});
295+
});
296+
271297
contract('UFragmentsPolicy:Rebase', async function (accounts) {
272298
before('setup UFragmentsPolicy contract', setupContractsWithOpenRebaseWindow);
273299

0 commit comments

Comments
 (0)