mirror of
https://github.com/status-im/codex-contracts-eth.git
synced 2025-02-07 14:13:28 +00:00
vault: combine Account and Flow structs
This commit is contained in:
parent
25d9c15ca7
commit
8f5e0f14f8
52
contracts/vault/Accounts.sol
Normal file
52
contracts/vault/Accounts.sol
Normal file
@ -0,0 +1,52 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity 0.8.28;
|
||||
|
||||
import "./TokensPerSecond.sol";
|
||||
|
||||
struct Account {
|
||||
uint128 available;
|
||||
uint128 designated;
|
||||
TokensPerSecond flow;
|
||||
Timestamp flowUpdated;
|
||||
}
|
||||
|
||||
library Accounts {
|
||||
function isValidAt(
|
||||
Account memory account,
|
||||
Timestamp timestamp
|
||||
) internal pure returns (bool) {
|
||||
if (account.flow < TokensPerSecond.wrap(0)) {
|
||||
return uint128(-accumulateFlow(account, timestamp)) <= account.available;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function at(
|
||||
Account memory account,
|
||||
Timestamp timestamp
|
||||
) internal pure returns (Account memory) {
|
||||
Account memory result = account;
|
||||
if (result.flow != TokensPerSecond.wrap(0)) {
|
||||
int128 accumulated = accumulateFlow(result, timestamp);
|
||||
if (accumulated >= 0) {
|
||||
result.designated += uint128(accumulated);
|
||||
} else {
|
||||
result.available -= uint128(-accumulated);
|
||||
}
|
||||
}
|
||||
result.flowUpdated = timestamp;
|
||||
return result;
|
||||
}
|
||||
|
||||
function accumulateFlow(
|
||||
Account memory account,
|
||||
Timestamp timestamp
|
||||
) private pure returns (int128) {
|
||||
int128 rate = TokensPerSecond.unwrap(account.flow);
|
||||
Timestamp start = account.flowUpdated;
|
||||
Timestamp end = timestamp;
|
||||
uint64 duration = Timestamp.unwrap(end) - Timestamp.unwrap(start);
|
||||
return rate * int128(uint128(duration));
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity 0.8.28;
|
||||
|
||||
import "./Timestamps.sol";
|
||||
import "./TokensPerSecond.sol";
|
||||
|
||||
struct Flow {
|
||||
TokensPerSecond rate;
|
||||
Timestamp updated;
|
||||
}
|
||||
|
||||
library Flows {
|
||||
function totalAt(
|
||||
Flow memory flow,
|
||||
Timestamp timestamp
|
||||
) internal pure returns (int128) {
|
||||
int128 rate = TokensPerSecond.unwrap(flow.rate);
|
||||
Timestamp start = flow.updated;
|
||||
Timestamp end = timestamp;
|
||||
uint64 duration = Timestamp.unwrap(end) - Timestamp.unwrap(start);
|
||||
return rate * int128(uint128(duration));
|
||||
}
|
||||
}
|
@ -3,14 +3,14 @@ pragma solidity 0.8.28;
|
||||
|
||||
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
||||
import "./Accounts.sol";
|
||||
import "./Timestamps.sol";
|
||||
import "./TokensPerSecond.sol";
|
||||
import "./Flows.sol";
|
||||
import "./Locks.sol";
|
||||
|
||||
using SafeERC20 for IERC20;
|
||||
using Timestamps for Timestamp;
|
||||
using Flows for Flow;
|
||||
using Accounts for Account;
|
||||
using Locks for Lock;
|
||||
|
||||
abstract contract VaultBase {
|
||||
@ -20,12 +20,6 @@ abstract contract VaultBase {
|
||||
type Fund is bytes32;
|
||||
type Recipient is address;
|
||||
|
||||
struct Account {
|
||||
uint128 available;
|
||||
uint128 designated;
|
||||
Flow flow;
|
||||
}
|
||||
|
||||
mapping(Controller => mapping(Fund => Lock)) private _locks;
|
||||
mapping(Controller => mapping(Fund => mapping(Recipient => Account)))
|
||||
private _accounts;
|
||||
@ -47,19 +41,12 @@ abstract contract VaultBase {
|
||||
Recipient recipient
|
||||
) internal view returns (Account memory) {
|
||||
Account memory account = _accounts[controller][fund][recipient];
|
||||
Timestamp timestamp = Timestamps.currentTime();
|
||||
if (account.flow.rate != TokensPerSecond.wrap(0)) {
|
||||
Lock memory lock = _locks[controller][fund];
|
||||
Timestamp end = Timestamps.earliest(timestamp, lock.expiry);
|
||||
int128 accumulated = account.flow.totalAt(end);
|
||||
if (accumulated >= 0) {
|
||||
account.designated += uint128(accumulated);
|
||||
} else {
|
||||
account.available -= uint128(-accumulated);
|
||||
}
|
||||
}
|
||||
account.flow.updated = timestamp;
|
||||
return account;
|
||||
Lock memory lock = _locks[controller][fund];
|
||||
Timestamp timestamp = Timestamps.earliest(
|
||||
Timestamps.currentTime(),
|
||||
lock.expiry
|
||||
);
|
||||
return account.at(timestamp);
|
||||
}
|
||||
|
||||
function _lock(
|
||||
@ -165,8 +152,8 @@ abstract contract VaultBase {
|
||||
Account memory senderAccount = _getAccount(controller, fund, from);
|
||||
Account memory receiverAccount = _getAccount(controller, fund, to);
|
||||
|
||||
senderAccount.flow.rate = senderAccount.flow.rate - rate;
|
||||
receiverAccount.flow.rate = receiverAccount.flow.rate + rate;
|
||||
senderAccount.flow = senderAccount.flow - rate;
|
||||
receiverAccount.flow = receiverAccount.flow + rate;
|
||||
|
||||
_checkAccountInvariant(senderAccount, lock);
|
||||
|
||||
@ -183,10 +170,7 @@ abstract contract VaultBase {
|
||||
require(lock.isLocked(), LockRequired());
|
||||
|
||||
Account memory account = _getAccount(controller, fund, recipient);
|
||||
require(
|
||||
account.flow.rate == TokensPerSecond.wrap(0),
|
||||
CannotBurnFlowingTokens()
|
||||
);
|
||||
require(account.flow == TokensPerSecond.wrap(0), CannotBurnFlowingTokens());
|
||||
|
||||
uint128 amount = account.available + account.designated;
|
||||
|
||||
@ -229,10 +213,7 @@ abstract contract VaultBase {
|
||||
Account memory account,
|
||||
Lock memory lock
|
||||
) private pure {
|
||||
if (account.flow.rate < TokensPerSecond.wrap(0)) {
|
||||
uint128 outgoing = uint128(-account.flow.totalAt(lock.maximum));
|
||||
require(outgoing <= account.available, InsufficientBalance());
|
||||
}
|
||||
require(account.isValidAt(lock.maximum), InsufficientBalance());
|
||||
}
|
||||
|
||||
error InsufficientBalance();
|
||||
|
Loading…
x
Reference in New Issue
Block a user