mirror of
https://github.com/logos-storage/logos-storage-contracts-eth.git
synced 2026-01-04 06:13:09 +00:00
vault: burn entire fund
This commit is contained in:
parent
682b65b24a
commit
bbdd614579
@ -79,6 +79,11 @@ contract Vault is VaultBase {
|
||||
_burn(controller, fund, recipient);
|
||||
}
|
||||
|
||||
function burnAll(Fund fund) public {
|
||||
Controller controller = Controller.wrap(msg.sender);
|
||||
_burnAll(controller, fund);
|
||||
}
|
||||
|
||||
function withdraw(Fund fund, Recipient recipient) public {
|
||||
Controller controller = Controller.wrap(msg.sender);
|
||||
_withdraw(controller, fund, recipient);
|
||||
|
||||
@ -7,10 +7,27 @@ struct Lock {
|
||||
Timestamp expiry;
|
||||
Timestamp maximum;
|
||||
uint128 value;
|
||||
bool burned;
|
||||
}
|
||||
|
||||
enum LockStatus {
|
||||
NoLock,
|
||||
Locked,
|
||||
Unlocked,
|
||||
Burned
|
||||
}
|
||||
|
||||
library Locks {
|
||||
function isLocked(Lock memory lock) internal view returns (bool) {
|
||||
return Timestamps.currentTime() < lock.expiry;
|
||||
function status(Lock memory lock) internal view returns (LockStatus) {
|
||||
if (lock.burned) {
|
||||
return LockStatus.Burned;
|
||||
}
|
||||
if (Timestamps.currentTime() < lock.expiry) {
|
||||
return LockStatus.Locked;
|
||||
}
|
||||
if (lock.maximum == Timestamp.wrap(0)) {
|
||||
return LockStatus.NoLock;
|
||||
}
|
||||
return LockStatus.Unlocked;
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,14 +40,19 @@ abstract contract VaultBase {
|
||||
Fund fund,
|
||||
Recipient recipient
|
||||
) internal view returns (Balance memory) {
|
||||
Account memory account = _accounts[controller][fund][recipient];
|
||||
Lock memory lock = _locks[controller][fund];
|
||||
if (lock.isLocked()) {
|
||||
LockStatus lockStatus = lock.status();
|
||||
if (lockStatus == LockStatus.Locked) {
|
||||
Account memory account = _accounts[controller][fund][recipient];
|
||||
account.update(Timestamps.currentTime());
|
||||
} else {
|
||||
account.update(lock.expiry);
|
||||
return account.balance;
|
||||
}
|
||||
return account.balance;
|
||||
if (lockStatus == LockStatus.Unlocked) {
|
||||
Account memory account = _accounts[controller][fund][recipient];
|
||||
account.update(lock.expiry);
|
||||
return account.balance;
|
||||
}
|
||||
return Balance({available: 0, designated: 0});
|
||||
}
|
||||
|
||||
function _lock(
|
||||
@ -70,7 +75,7 @@ abstract contract VaultBase {
|
||||
Timestamp expiry
|
||||
) internal {
|
||||
Lock memory lock = _locks[controller][fund];
|
||||
require(lock.isLocked(), LockRequired());
|
||||
require(lock.status() == LockStatus.Locked, LockRequired());
|
||||
require(lock.expiry <= expiry, InvalidExpiry());
|
||||
lock.expiry = expiry;
|
||||
_checkLockInvariant(lock);
|
||||
@ -84,7 +89,7 @@ abstract contract VaultBase {
|
||||
uint128 amount
|
||||
) internal {
|
||||
Lock storage lock = _locks[controller][fund];
|
||||
require(lock.isLocked(), LockRequired());
|
||||
require(lock.status() == LockStatus.Locked, LockRequired());
|
||||
|
||||
Account storage account = _accounts[controller][fund][recipient];
|
||||
|
||||
@ -105,7 +110,7 @@ abstract contract VaultBase {
|
||||
uint128 amount
|
||||
) internal {
|
||||
Lock memory lock = _locks[controller][fund];
|
||||
require(lock.isLocked(), LockRequired());
|
||||
require(lock.status() == LockStatus.Locked, LockRequired());
|
||||
|
||||
Account memory account = _accounts[controller][fund][recipient];
|
||||
require(amount <= account.balance.available, InsufficientBalance());
|
||||
@ -125,7 +130,7 @@ abstract contract VaultBase {
|
||||
uint128 amount
|
||||
) internal {
|
||||
Lock memory lock = _locks[controller][fund];
|
||||
require(lock.isLocked(), LockRequired());
|
||||
require(lock.status() == LockStatus.Locked, LockRequired());
|
||||
|
||||
Account memory sender = _accounts[controller][fund][from];
|
||||
require(amount <= sender.balance.available, InsufficientBalance());
|
||||
@ -146,7 +151,7 @@ abstract contract VaultBase {
|
||||
TokensPerSecond rate
|
||||
) internal {
|
||||
Lock memory lock = _locks[controller][fund];
|
||||
require(lock.isLocked(), LockRequired());
|
||||
require(lock.status() == LockStatus.Locked, LockRequired());
|
||||
|
||||
Account memory sender = _accounts[controller][fund][from];
|
||||
sender.flowOut(rate);
|
||||
@ -164,7 +169,7 @@ abstract contract VaultBase {
|
||||
Recipient recipient
|
||||
) internal {
|
||||
Lock storage lock = _locks[controller][fund];
|
||||
require(lock.isLocked(), LockRequired());
|
||||
require(lock.status() == LockStatus.Locked, LockRequired());
|
||||
|
||||
Account memory account = _accounts[controller][fund][recipient];
|
||||
require(account.flow.incoming == account.flow.outgoing, FlowMustBeZero());
|
||||
@ -177,13 +182,23 @@ abstract contract VaultBase {
|
||||
_token.safeTransfer(address(0xdead), amount);
|
||||
}
|
||||
|
||||
function _burnAll(
|
||||
Controller controller,
|
||||
Fund fund
|
||||
) internal {
|
||||
Lock storage lock = _locks[controller][fund];
|
||||
require(lock.status() == LockStatus.Locked, LockRequired());
|
||||
|
||||
lock.burned = true;
|
||||
}
|
||||
|
||||
function _withdraw(
|
||||
Controller controller,
|
||||
Fund fund,
|
||||
Recipient recipient
|
||||
) internal {
|
||||
Lock memory lock = _locks[controller][fund];
|
||||
require(!lock.isLocked(), Locked());
|
||||
require(lock.status() == LockStatus.Unlocked, Locked());
|
||||
|
||||
Account memory account = _accounts[controller][fund][recipient];
|
||||
account.update(lock.expiry);
|
||||
|
||||
@ -56,8 +56,8 @@ describe("Vault", function () {
|
||||
await expect(locking).to.be.revertedWith("ExpiryPastMaximum")
|
||||
})
|
||||
|
||||
describe("unlocked fund", function () {
|
||||
testUnlockedFund()
|
||||
describe("fund is not locked", function () {
|
||||
testFundThatIsNotLocked()
|
||||
})
|
||||
})
|
||||
|
||||
@ -501,6 +501,15 @@ describe("Vault", function () {
|
||||
await vault.flow(fund, account2.address, account.address, 5)
|
||||
await expect(vault.burn(fund, account.address)).not.to.be.reverted
|
||||
})
|
||||
|
||||
it("can burn an entire fund", async function () {
|
||||
await vault.transfer(fund, account.address, account2.address, 10)
|
||||
await vault.transfer(fund, account.address, account3.address, 10)
|
||||
await vault.burnAll(fund)
|
||||
await expect(await vault.getBalance(fund, account.address)).to.equal(0)
|
||||
await expect(await vault.getBalance(fund, account2.address)).to.equal(0)
|
||||
await expect(await vault.getBalance(fund, account3.address)).to.equal(0)
|
||||
})
|
||||
})
|
||||
|
||||
describe("withdrawing", function () {
|
||||
@ -630,6 +639,8 @@ describe("Vault", function () {
|
||||
setAutomine(true)
|
||||
await token.connect(controller).approve(vault.address, amount)
|
||||
await vault.deposit(fund, account.address, amount)
|
||||
await token.connect(controller).approve(vault.address, amount)
|
||||
await vault.deposit(fund, account2.address, amount)
|
||||
})
|
||||
|
||||
it("allows controller to withdraw for a recipient", async function () {
|
||||
@ -676,16 +687,16 @@ describe("Vault", function () {
|
||||
})
|
||||
|
||||
it("can withdraw funds that were transfered in", async function () {
|
||||
await vault.transfer(fund, account.address, account2.address, amount)
|
||||
await vault.transfer(fund, account.address, account3.address, amount)
|
||||
await expire()
|
||||
const before = await token.balanceOf(account2.address)
|
||||
await vault.withdraw(fund, account2.address)
|
||||
const after = await token.balanceOf(account2.address)
|
||||
const before = await token.balanceOf(account3.address)
|
||||
await vault.withdraw(fund, account3.address)
|
||||
const after = await token.balanceOf(account3.address)
|
||||
expect(after - before).to.equal(amount)
|
||||
})
|
||||
|
||||
it("cannot withdraw funds that were transfered out", async function () {
|
||||
await vault.transfer(fund, account.address, account2.address, amount)
|
||||
await vault.transfer(fund, account.address, account3.address, amount)
|
||||
await expire()
|
||||
const before = await token.balanceOf(account.address)
|
||||
await vault.withdraw(fund, account.address)
|
||||
@ -712,17 +723,55 @@ describe("Vault", function () {
|
||||
})
|
||||
})
|
||||
|
||||
describe("unlocked fund", function () {
|
||||
describe("fund is not locked", function () {
|
||||
beforeEach(async function() {
|
||||
setAutomine(true)
|
||||
await expire()
|
||||
})
|
||||
|
||||
testUnlockedFund()
|
||||
testFundThatIsNotLocked()
|
||||
})
|
||||
})
|
||||
|
||||
function testUnlockedFund() {
|
||||
describe("when a fund is burned", function () {
|
||||
const amount = 1000
|
||||
|
||||
let expiry
|
||||
|
||||
beforeEach(async function () {
|
||||
expiry = (await currentTime()) + 100
|
||||
await token.connect(controller).approve(vault.address, amount)
|
||||
await vault.lock(fund, expiry, expiry)
|
||||
await vault.deposit(fund, account.address, amount)
|
||||
await vault.burnAll(fund)
|
||||
})
|
||||
|
||||
testBurnedFund()
|
||||
|
||||
describe("when the lock expires", function () {
|
||||
beforeEach(async function () {
|
||||
await advanceTimeTo(expiry)
|
||||
})
|
||||
|
||||
testBurnedFund()
|
||||
})
|
||||
|
||||
function testBurnedFund() {
|
||||
it("cannot set lock", async function () {
|
||||
const locking = vault.lock(fund, expiry, maximum)
|
||||
await expect(locking).to.be.revertedWith("AlreadyLocked")
|
||||
})
|
||||
|
||||
it("cannot withdraw", async function () {
|
||||
const withdrawing = vault.withdraw(fund, account.address)
|
||||
await expect(withdrawing).to.be.revertedWith("Locked")
|
||||
})
|
||||
|
||||
testFundThatIsNotLocked()
|
||||
}
|
||||
})
|
||||
|
||||
function testFundThatIsNotLocked() {
|
||||
it("does not allow extending of lock", async function () {
|
||||
await expect(
|
||||
vault.extendLock(fund, (await currentTime()) + 1)
|
||||
@ -755,10 +804,14 @@ describe("Vault", function () {
|
||||
).to.be.revertedWith("LockRequired")
|
||||
})
|
||||
|
||||
it("does not allow burning of tokens", async function () {
|
||||
it("does not allow burning of accounts", async function () {
|
||||
await expect(vault.burn(fund, account.address)).to.be.revertedWith(
|
||||
"LockRequired"
|
||||
)
|
||||
})
|
||||
|
||||
it("does not allow burning an entire fund", async function () {
|
||||
await expect(vault.burnAll(fund)).to.be.revertedWith("LockRequired")
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user