Skip to content
This repository has been archived by the owner on Oct 26, 2022. It is now read-only.

Commit

Permalink
feat: lock on first deposit
Browse files Browse the repository at this point in the history
  • Loading branch information
gasper committed Jan 5, 2022
1 parent a8310bb commit 6196eab
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 27 deletions.
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{
"files.eol": "\n"
"files.eol": "\n",
"solidity.defaultCompiler": "remote"
}
10 changes: 5 additions & 5 deletions contracts/BentoBox.sol
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,6 @@ contract BentoBox is MasterContractManager, BoringBatchable {
IERC20 token = token_ == USE_ETHEREUM ? wethToken : token_;
Rebase memory total = totals[token];

// If a new token gets added, the tokenSupply call checks that this is a deployed contract. Needed for security.
require(total.elastic != 0 || token.totalSupply() > 0, "BentoBox: No tokens");
if (share == 0) {
// value of the share may be lower than the amount due to rounding, that's ok
share = total.toBase(amount, false);
Expand All @@ -207,9 +205,13 @@ contract BentoBox is MasterContractManager, BoringBatchable {
"BentoBox: Skim too much"
);

balanceOf[token][to] = balanceOf[token][to].add(share);
total.base = total.base.add(share.to128());
if (total.elastic == 0) {
// Upon the first deposit permanently lock the MINIMUM_SHARE_BALANCE amount of tokens
share = share.sub(MINIMUM_SHARE_BALANCE);
}
total.elastic = total.elastic.add(amount.to128());
balanceOf[token][to] = balanceOf[token][to].add(share);
totals[token] = total;

// Interactions
Expand Down Expand Up @@ -258,8 +260,6 @@ contract BentoBox is MasterContractManager, BoringBatchable {
balanceOf[token][from] = balanceOf[token][from].sub(share);
total.elastic = total.elastic.sub(amount.to128());
total.base = total.base.sub(share.to128());
// There have to be at least 1000 shares left to prevent reseting the share/amount ratio (unless it's fully emptied)
require(total.base >= MINIMUM_SHARE_BALANCE || total.base == 0, "BentoBox: cannot empty");
totals[token] = total;

// Interactions
Expand Down
40 changes: 21 additions & 19 deletions test/BentoBox.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ describe("BentoBox", function () {
.to.emit(this.a, "Transfer")
.withArgs(this.fred.address, this.bentoBox.address, getBigNumber(100))
.to.emit(this.bentoBox, "LogDeposit")
.withArgs(this.a.address, this.fred.address, this.fred.address, getBigNumber(100), getBigNumber(100))
.withArgs(this.a.address, this.fred.address, this.fred.address, getBigNumber(100), getBigNumber(100).sub(1000))

this.bentoBox.connect(this.fred).addProfit(this.a.address, getBigNumber(30))

Expand All @@ -64,7 +64,7 @@ describe("BentoBox", function () {
.to.emit(this.b, "Transfer")
.withArgs(this.fred.address, this.bentoBox.address, getBigNumber(200, 6))
.to.emit(this.bentoBox, "LogDeposit")
.withArgs(this.b.address, this.fred.address, this.fred.address, getBigNumber(200, 6), getBigNumber(200, 6))
.withArgs(this.b.address, this.fred.address, this.fred.address, getBigNumber(200, 6), getBigNumber(200, 6).sub(1000))

this.bentoBox.connect(this.fred).addProfit(this.b.address, getBigNumber(200, 6))

Expand Down Expand Up @@ -249,19 +249,21 @@ describe("BentoBox", function () {
.to.emit(this.weth9, "Deposit")
.withArgs(this.bentoBox.address, "1000")
.to.emit(this.bentoBox, "LogDeposit")
.withArgs(this.weth9.address, this.bob.address, this.bob.address, "1000", "1000")
.withArgs(this.weth9.address, this.bob.address, this.bob.address, "1000", "0")

expect(await this.weth9.balanceOf(this.bentoBox.address), "BentoBox should hold WETH").to.be.equal(1000)
expect(await this.bentoBox.balanceOf(this.weth9.address, this.bob.address), "bob shouldn't have weth").to.be.equal(0)
await this.bentoBox.connect(this.bob).deposit(ADDRESS_ZERO, this.bob.address, this.bob.address, 1000, 0, { value: 1000 })
expect(await this.bentoBox.balanceOf(this.weth9.address, this.bob.address), "bob should have weth").to.be.equal(1000)
})

it("Reverts if TotalSupply of token is Zero or if token isn't a token", async function () {
it("Reverts if token isn't a token", async function () {
// await expect(
// this.bentoBox.connect(this.bob).deposit(ADDRESS_ZERO, this.bob.address, this.bob.address, 1, 0, { value: 1 })
// ).to.be.revertedWith("BentoBox: No tokens")
await expect(
this.bentoBox.connect(this.bob).deposit(ADDRESS_ZERO, this.bob.address, this.bob.address, 1, 0, { value: 1 })
).to.be.revertedWith("BentoBox: No tokens")
await expect(
this.bentoBox.connect(this.bob).deposit(this.bentoBox.address, this.bob.address, this.bob.address, 1, 0, { value: 1 })
).to.be.revertedWith("Transaction reverted: function selector was not recognized and there's no fallback function")
this.bentoBox.connect(this.bob).deposit(this.bentoBox.address, this.bob.address, this.bob.address, 1000, 0)
).to.be.revertedWith("VM Exception while processing transaction: revert BoringERC20: TransferFrom failed")
})

it("Mutates balanceOf and totalSupply for two deposits correctly", async function () {
Expand Down Expand Up @@ -327,15 +329,15 @@ describe("BentoBox", function () {

it("should not allow grieving attack with deposit of Share", async function () {
await this.c.approve(this.bentoBox.address, 1000000000000)
await this.bentoBox.deposit(this.c.address, this.alice.address, this.alice.address, 0, 1)
await this.bentoBox.deposit(this.c.address, this.alice.address, this.c.address, 0, 1000)
await this.bentoBox.addProfit(this.c.address, 1)
let amount = 2
for (let i = 0; i < 20; i++) {
await this.bentoBox.deposit(this.c.address, this.alice.address, this.alice.address, amount - 1, 0)
amount += amount - 1
}
const ratio =
(await this.bentoBox.totals(this.c.address)).elastic / (await this.bentoBox.balanceOf(this.c.address, this.alice.address))
(await this.bentoBox.totals(this.c.address)).elastic.sub(1000) / (await this.bentoBox.balanceOf(this.c.address, this.alice.address))
expect(ratio).to.be.lessThan(5)
})
})
Expand Down Expand Up @@ -374,10 +376,10 @@ describe("BentoBox", function () {
.to.emit(this.a, "Transfer")
.withArgs(this.alice.address, this.bento.address, "1000")
.to.emit(this.bento, "LogDeposit")
.withArgs(this.a.address, this.alice.address, this.alice.address, "1000", "1000")
.withArgs(this.a.address, this.alice.address, this.alice.address, "1000", "0")

await expect(this.bento.withdraw(this.a.address, this.alice.address, this.alice.address, 0, 2)).to.be.revertedWith(
"BentoBox: cannot empty"
await expect(this.bento.withdraw(this.a.address, this.alice.address, this.alice.address, 0, 1)).to.be.revertedWith(
"VM Exception while processing transaction: revert BoringMath: Underflow"
)
})

Expand Down Expand Up @@ -447,7 +449,7 @@ describe("BentoBox", function () {
from: this.bob.address,
})

expect(await this.bentoBox.balanceOf(this.weth9.address, this.bob.address), "token should be withdrawn").to.be.equal(100000)
expect(await this.bentoBox.balanceOf(this.weth9.address, this.bob.address), "token should be withdrawn").to.be.equal(100000 - 1000)
})

it("Reverts if ETH transfer fails", async function () {
Expand Down Expand Up @@ -714,20 +716,20 @@ describe("BentoBox", function () {
describe("Skim ETH", function () {
it("Skims ether to from address", async function () {
await this.weth9.connect(this.alice).deposit({
value: 1000,
value: 2000,
})

await this.bentoBox.batch([], true, {
value: 1000,
value: 2000,
})

await this.bentoBox.deposit(ADDRESS_ZERO, this.bentoBox.address, this.alice.address, 1000, 0)
await this.bentoBox.deposit(ADDRESS_ZERO, this.bentoBox.address, this.alice.address, 2000, 0)

amount = await this.bentoBox.balanceOf(this.weth9.address, this.alice.address)

expect(amount, "alice should have weth").to.equal(1000)

expect(await this.weth9.balanceOf(this.bentoBox.address), "BentoBox should hold WETH").to.equal(1000)
expect(await this.weth9.balanceOf(this.bentoBox.address), "BentoBox should hold WETH").to.equal(2000)
})
})

Expand Down
2 changes: 1 addition & 1 deletion test/HelloWorld.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ describe("HelloWorld", function () {

it("should allow deposit", async function () {
await this.helloWorld.deposit(APPROVAL_AMOUNT)
assert.equal((await this.helloWorld.balance()).toString(), APPROVAL_AMOUNT.toString())
assert.equal((await this.helloWorld.balance()).toString(), (APPROVAL_AMOUNT - 1000).toString())
})

it("should allow withdraw", async function () {
Expand Down
2 changes: 1 addition & 1 deletion test/harness/harvest.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ describe("DummyStrategyMock", function () {
it("check balances of BentoBox", async function () {
assert.equal(
(await this.bentoBox.balanceOf(this.tokenA.address, this.alice.address)).toString(),
getBigNumber(DEPOSIT_AMOUNT, await this.tokenA.decimals()).toString(),
getBigNumber(DEPOSIT_AMOUNT, await this.tokenA.decimals()).sub(1000).toString(),
"should match deposit amount"
)

Expand Down

0 comments on commit 6196eab

Please sign in to comment.