forked from compound-finance/comet
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
withdrawReserves (compound-finance#141)
* withdrawReserves, tests, scenarios * update scenario * update unit tests * simplify governor withdraws scenario * confirm albert baseToken balance * update require message * do transfer out * delete ReservesWithdrawn event * confirm comet balance in unit test * insufficient reserves check * additional unit test * inline reserves * typo
- Loading branch information
1 parent
df8a12f
commit a6588a8
Showing
8 changed files
with
234 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import { scenario } from './context/CometContext'; | ||
import { expect } from 'chai'; | ||
|
||
scenario( | ||
'Comet#withdrawReserves > governor withdraw reserves', | ||
{ | ||
baseToken: { | ||
balance: 100, | ||
}, | ||
upgrade: true, | ||
}, | ||
async ({ comet, actors, getAssetByAddress }) => { | ||
const { admin, albert } = actors; | ||
|
||
const baseToken = getAssetByAddress(await comet.baseToken()); | ||
|
||
expect(await baseToken.balanceOf(comet.address)).to.equal(100n); | ||
|
||
await admin.withdrawReserves(albert, 10); | ||
|
||
expect(await baseToken.balanceOf(comet.address)).to.equal(90n); | ||
expect(await baseToken.balanceOf(albert.address)).to.equal(10n); | ||
} | ||
); | ||
|
||
scenario( | ||
'Comet#withdrawReserves > reverts if not called by governor', | ||
{ | ||
baseToken: { | ||
balance: 100, | ||
}, | ||
upgrade: true, | ||
}, | ||
async ({ actors }) => { | ||
const { albert } = actors; | ||
await expect(albert.withdrawReserves(albert, 10)).to.be.revertedWith( | ||
'only governor may withdraw' | ||
); | ||
} | ||
); | ||
|
||
scenario( | ||
'Comet#withdrawReserves > reverts if not enough reserves are owned by protocol', | ||
{ | ||
baseToken: { | ||
balance: 100, | ||
}, | ||
upgrade: true, | ||
}, | ||
async ({ actors }) => { | ||
const { admin, albert } = actors; | ||
|
||
await expect(admin.withdrawReserves(albert, 101)).to.be.revertedWith('insufficient reserves'); | ||
} | ||
); | ||
|
||
// XXX add scenario that tests for a revert when reserves are reduced by | ||
// totalSupplyBase |
36 changes: 36 additions & 0 deletions
36
scenario/constraints/BaseTokenProtocolBalanceConstraint.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { Constraint, World } from '../../plugins/scenario'; | ||
import { CometContext } from '../context/CometContext'; | ||
import { expect } from 'chai'; | ||
|
||
export class BaseTokenProtocolBalanceConstraint<T extends CometContext> implements Constraint<T> { | ||
async solve(requirements: object, context: T, world: World) { | ||
const baseTokenRequirements = requirements['baseToken']; | ||
if (!baseTokenRequirements) { | ||
return null; | ||
} | ||
if (typeof baseTokenRequirements['balance'] !== 'undefined') { | ||
return async (context: CometContext) => { | ||
const { comet } = context; | ||
const amount = baseTokenRequirements['balance']; | ||
const baseToken = context.getAssetByAddress(await comet.baseToken()); | ||
|
||
await context.sourceTokens(world, amount, baseToken, comet.address); | ||
}; | ||
} | ||
} | ||
|
||
async check(requirements: object, context: T, world: World) { | ||
const baseTokenRequirements = requirements['baseToken']; | ||
if (!baseTokenRequirements) { | ||
return null; | ||
} | ||
if (typeof baseTokenRequirements['balance'] !== 'undefined') { | ||
const amount = baseTokenRequirements['balance']; | ||
const { comet } = context; | ||
|
||
const baseToken = context.getAssetByAddress(await comet.baseToken()); | ||
|
||
expect(await baseToken.balanceOf(comet.address)).to.equal(BigInt(amount)); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import { expect, makeProtocol, wait, filterEvent } from './helpers'; | ||
|
||
describe('withdrawReserves', function () { | ||
it('withdraws reserves from the protocol', async () => { | ||
const tokenBalance = 1000; | ||
const { | ||
comet, | ||
tokens: { USDC }, | ||
users: [alice], | ||
governor, | ||
} = await makeProtocol({ | ||
baseTokenBalance: tokenBalance, | ||
}); | ||
|
||
expect(await USDC.balanceOf(alice.address)).to.be.equal(0); | ||
await comet.connect(governor).withdrawReserves(alice.address, tokenBalance); | ||
expect(await USDC.balanceOf(alice.address)).to.equal(tokenBalance); | ||
expect(await USDC.balanceOf(comet.address)).to.equal(0); | ||
}); | ||
|
||
it('reverts if called not by governor', async () => { | ||
const { | ||
comet, | ||
users: [alice], | ||
} = await makeProtocol(); | ||
await expect(comet.connect(alice).withdrawReserves(alice.address, 10)).to.be.revertedWith( | ||
'only governor may withdraw' | ||
); | ||
}); | ||
|
||
it('reverts if not enough reserves are owned by protocol', async () => { | ||
const tokenBalance = 1000; | ||
const { | ||
comet, | ||
governor, | ||
users: [alice], | ||
} = await makeProtocol({ | ||
baseTokenBalance: tokenBalance, | ||
}); | ||
await expect( | ||
comet.connect(governor).withdrawReserves(alice.address, tokenBalance + 1) | ||
).to.be.revertedWith('insufficient reserves'); | ||
}); | ||
|
||
it('accounts for total supply base when calculating reserves', async () => { | ||
const { | ||
comet, | ||
governor, | ||
users: [alice], | ||
} = await makeProtocol({ | ||
baseTokenBalance: 200, | ||
}); | ||
|
||
const totalsBasic = await comet.totalsBasic(); | ||
|
||
await wait( | ||
comet.setTotalsBasic({ | ||
...totalsBasic, | ||
totalSupplyBase: 100n, | ||
}) | ||
); | ||
|
||
expect(await comet.getReserves()).to.be.equal(100); | ||
|
||
await expect(comet.connect(governor).withdrawReserves(alice.address, 101)).to.be.revertedWith( | ||
'insufficient reserves' | ||
); | ||
}); | ||
}); |