From 6e531f2087dddc2e9e347ccc7ee3db011302c7f9 Mon Sep 17 00:00:00 2001 From: Mark Spanbroek Date: Mon, 3 Feb 2025 16:26:51 +0100 Subject: [PATCH] vault: only allow deposit, transfer, etc when locked --- contracts/vault/VaultBase.sol | 22 +++++++++--- test/Vault.tests.js | 63 +++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 4 deletions(-) diff --git a/contracts/vault/VaultBase.sol b/contracts/vault/VaultBase.sol index 313059e..af2453b 100644 --- a/contracts/vault/VaultBase.sol +++ b/contracts/vault/VaultBase.sol @@ -79,9 +79,18 @@ abstract contract VaultBase { address from, uint128 amount ) internal { + Lock memory lock = _locks[controller][context]; + require(lock.isLocked(), LockRequired()); + Recipient recipient = Recipient.wrap(from); - _balances[controller][context][recipient].available += amount; - _locks[controller][context].value += amount; + Balance memory balance = _balances[controller][context][recipient]; + + balance.available += amount; + lock.value += amount; + + _balances[controller][context][recipient] = balance; + _locks[controller][context] = lock; + _token.safeTransferFrom(from, address(this), amount); } @@ -123,6 +132,7 @@ abstract contract VaultBase { Recipient recipient ) internal { Lock memory lock = _locks[controller][context]; + require(lock.isLocked(), LockRequired()); Flow memory flow = _flows[controller][context][recipient]; require(flow.rate == TokensPerSecond.wrap(0), CannotBurnFlowingTokens()); @@ -150,6 +160,9 @@ abstract contract VaultBase { Recipient to, uint128 amount ) internal { + Lock memory lock = _locks[controller][context]; + require(lock.isLocked(), LockRequired()); + Balance memory senderBalance = _getBalance(controller, context, from); Balance memory receiverBalance = _getBalance(controller, context, to); require(amount <= senderBalance.available, InsufficientBalance()); @@ -158,7 +171,6 @@ abstract contract VaultBase { receiverBalance.available += amount; Flow memory senderFlow = _flows[controller][context][from]; - Lock memory lock = _locks[controller][context]; _checkFlowInvariant(senderBalance, lock, senderFlow); _balances[controller][context][from] = senderBalance; @@ -171,6 +183,9 @@ abstract contract VaultBase { Recipient recipient, uint128 amount ) internal { + Lock memory lock = _locks[controller][context]; + require(lock.isLocked(), LockRequired()); + Balance memory balance = _balances[controller][context][recipient]; require(amount <= balance.available, InsufficientBalance()); @@ -178,7 +193,6 @@ abstract contract VaultBase { balance.designated += amount; Flow memory flow = _flows[controller][context][recipient]; - Lock memory lock = _locks[controller][context]; _checkFlowInvariant(balance, lock, flow); _balances[controller][context][recipient] = balance; diff --git a/test/Vault.tests.js b/test/Vault.tests.js index 7feb11c..a6e4c56 100644 --- a/test/Vault.tests.js +++ b/test/Vault.tests.js @@ -56,12 +56,37 @@ describe("Vault", function () { ).to.be.revertedWith("LockRequired") }) + it("does not allow depositing of tokens", async function () { + const amount = 1000 + await token.connect(account).approve(vault.address, amount) + await expect( + vault.deposit(context, account.address, amount) + ).to.be.revertedWith("LockRequired") + }) + + it("does not allow designating tokens", async function () { + await expect( + vault.designate(context, account.address, 0) + ).to.be.revertedWith("LockRequired") + }) + + it("does not allow transfer of tokens", async function () { + await expect( + vault.transfer(context, account.address, account2.address, 0) + ).to.be.revertedWith("LockRequired") + }) + it("does not allow flowing of tokens", async function () { await expect( vault.flow(context, account.address, account2.address, 0) ).to.be.revertedWith("LockRequired") }) + it("does not allow burning of tokens", async function () { + await expect(vault.burn(context, account.address)).to.be.revertedWith( + "LockRequired" + ) + }) }) describe("when lock is locked", function () { @@ -143,6 +168,8 @@ describe("Vault", function () { it("separates deposits from different contexts", async function () { const context1 = randomBytes(32) const context2 = randomBytes(32) + await vault.lock(context1, expiry, maximum) + await vault.lock(context2, expiry, maximum) await token.connect(account).approve(vault.address, 3) await vault.deposit(context1, account.address, 1) await vault.deposit(context2, account.address, 2) @@ -154,6 +181,8 @@ describe("Vault", function () { const [, , controller1, controller2] = await ethers.getSigners() const vault1 = vault.connect(controller1) const vault2 = vault.connect(controller2) + await vault1.lock(context, expiry, maximum) + await vault2.lock(context, expiry, maximum) await token.connect(account).approve(vault.address, 3) await vault1.deposit(context, account.address, 1) await vault2.deposit(context, account.address, 2) @@ -689,5 +718,39 @@ describe("Vault", function () { expect(after).to.equal(before) }) }) + + it("does not allow depositing of tokens", async function () { + setAutomine(true) + await expire() + const amount = 1000 + await token.connect(account).approve(vault.address, amount) + await expect( + vault.deposit(context, account.address, amount) + ).to.be.revertedWith("LockRequired") + }) + + it("does not allow designating tokens", async function () { + setAutomine(true) + await expire() + await expect( + vault.designate(context, account.address, 0) + ).to.be.revertedWith("LockRequired") + }) + + it("does not allow transfer of tokens", async function () { + setAutomine(true) + await expire() + await expect( + vault.transfer(context, account.address, account2.address, 0) + ).to.be.revertedWith("LockRequired") + }) + + it("does not allow burning of tokens", async function () { + setAutomine(true) + await expire() + await expect(vault.burn(context, account.address)).to.be.revertedWith( + "LockRequired" + ) + }) }) })