Skip to content

Commit

Permalink
(InflationaryERC20): simplify conversion demurrage to inflationary, r…
Browse files Browse the repository at this point in the history
…emove extension; clean up dead code
  • Loading branch information
benjaminbollen committed Oct 10, 2024
1 parent b21dcc2 commit 188cbb7
Show file tree
Hide file tree
Showing 7 changed files with 25 additions and 70 deletions.
13 changes: 0 additions & 13 deletions src/circles/Demurrage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -261,17 +261,4 @@ contract Demurrage is ICirclesCompactErrors, ICirclesDemurrageErrors {
// and do not cache it
return Math64x64.pow(GAMMA_64x64, _dayDifference);
}

/**
* Calculate the inflationary balance of a demurraged balance
* @param _balance Demurraged balance to calculate the inflationary balance of
* @param _dayUpdated The day the balance was last updated
*/
function _calculateInflationaryBalance(uint256 _balance, uint256 _dayUpdated) internal pure returns (uint256) {
// calculate the inflationary balance by dividing the balance by GAMMA^days
// note: GAMMA < 1, so dividing by a power of it, returns a bigger number,
// so the numerical imprecision is in the least significant bits.
int128 i = Math64x64.pow(BETA_64x64, _dayUpdated);
return Math64x64.mulu(i, _balance);
}
}
10 changes: 0 additions & 10 deletions src/circles/DiscountedBalances.sol
Original file line number Diff line number Diff line change
Expand Up @@ -78,16 +78,6 @@ contract DiscountedBalances is Demurrage {

// Internal functions

/**
* @dev Calculate the inflationary balance of a discounted balance
* @param _account Address of the account to calculate the balance of
* @param _id Circles identifier for which to calculate the balance
*/
function _inflationaryBalanceOf(address _account, uint256 _id) internal view returns (uint256) {
DiscountedBalance memory discountedBalance = discountedBalances[_id][_account];
return _calculateInflationaryBalance(discountedBalance.balance, discountedBalance.lastUpdatedDay);
}

/**
* @dev Update the balance of an account for a given Circles identifier
* @param _account Address of the account to update the balance of
Expand Down
2 changes: 1 addition & 1 deletion src/circles/InflationaryOperator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,6 @@ contract InflationaryCirclesOperator is BatchedDemurrage {
function _inflationaryBalanceOf(address _account, uint256 _id) internal view returns (uint256) {
// retrieve the balance in demurrage units (of today)
uint256 balance = hub.balanceOf(_account, _id);
return _calculateInflationaryBalance(balance, day(block.timestamp));
return convertDemurrageToInflationaryValue(balance, day(block.timestamp));
}
}
4 changes: 2 additions & 2 deletions src/lift/DemurrageCircles.sol
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ contract DemurrageCircles is MasterCopyNonUpgradable, ERC20DiscountedBalances, E
_burn(msg.sender, _amount);
hub.safeTransferFrom(address(this), msg.sender, toTokenId(avatar), _amount, "");

uint256 inflationaryAmount = _calculateInflationaryBalance(_amount, day(block.timestamp));
uint256 inflationaryAmount = convertDemurrageToInflationaryValue(_amount, day(block.timestamp));

emit WithdrawDemurraged(msg.sender, _amount, inflationaryAmount);
}
Expand Down Expand Up @@ -107,7 +107,7 @@ contract DemurrageCircles is MasterCopyNonUpgradable, ERC20DiscountedBalances, E
if (_id != toTokenId(avatar)) revert CirclesInvalidCirclesId(_id, 0);
_mint(_from, _amount);

uint256 inflationaryAmount = _calculateInflationaryBalance(_amount, day(block.timestamp));
uint256 inflationaryAmount = convertDemurrageToInflationaryValue(_amount, day(block.timestamp));

emit DepositDemurraged(_from, _amount, inflationaryAmount);

Expand Down
5 changes: 0 additions & 5 deletions src/lift/ERC20DiscountedBalances.sol
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,6 @@ contract ERC20DiscountedBalances is ERC20Permit, BatchedDemurrage, IERC20 {

// Internal functions

function _inflationaryBalanceOf(address _account) internal view returns (uint256) {
DiscountedBalance memory discountedBalance = discountedBalances[_account];
return _calculateInflationaryBalance(discountedBalance.balance, discountedBalance.lastUpdatedDay);
}

function _updateBalance(address _account, uint256 _balance, uint64 _day) internal {
if (_balance > MAX_VALUE) {
// Balance exceeds maximum value.
Expand Down
56 changes: 20 additions & 36 deletions src/lift/ERC20InflationaryBalances.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,11 @@ import "../circles/BatchedDemurrage.sol";
import "./ERC20Permit.sol";

contract ERC20InflationaryBalances is ERC20Permit, BatchedDemurrage, IERC20 {
// Constants

uint8 internal constant EXTENDED_ACCURACY_BITS = 64;

// State variables

uint256 internal _extendedTotalSupply;
uint256 internal _totalSupply;

mapping(address => uint256) private _extendedAccuracyBalances;
mapping(address => uint256) private _balances;

// Constructor

Expand Down Expand Up @@ -55,66 +51,54 @@ contract ERC20InflationaryBalances is ERC20Permit, BatchedDemurrage, IERC20 {
}

function balanceOf(address _account) external view returns (uint256) {
return _extendedAccuracyBalances[_account] >> EXTENDED_ACCURACY_BITS;
return _balances[_account];
}

function allowance(address _owner, address _spender) external view returns (uint256) {
return _allowances[_owner][_spender];
}

function totalSupply() external view returns (uint256) {
return _extendedTotalSupply >> EXTENDED_ACCURACY_BITS;
return _totalSupply;
}

// Internal functions

function _convertToExtended(uint256 _amount) internal pure returns (uint256) {
if (_amount > MAX_VALUE) revert CirclesAmountOverflow(_amount, 0);
return _amount << EXTENDED_ACCURACY_BITS;
}

function _transfer(address _from, address _to, uint256 _amount) internal {
uint256 extendedAmount = _convertToExtended(_amount);
uint256 extendedFromBalance = _extendedAccuracyBalances[_from];
if (extendedFromBalance < extendedAmount) {
revert ERC20InsufficientBalance(_from, extendedFromBalance >> EXTENDED_ACCURACY_BITS, _amount);
uint256 fromBalance = _balances[_from];
if (fromBalance < _amount) {
revert ERC20InsufficientBalance(_from, fromBalance, _amount);
}
unchecked {
_extendedAccuracyBalances[_from] = extendedFromBalance - extendedAmount;
_balances[_from] = fromBalance - _amount;
// rely on total supply not having overflowed
_extendedAccuracyBalances[_to] += extendedAmount;
_balances[_to] += _amount;
}
emit Transfer(_from, _to, _amount);
}

function _mintFromDemurragedAmount(address _owner, uint256 _demurragedAmount) internal returns (uint256) {
// first convert to extended accuracy representation so we have extra garbage bits,
// before we apply the inflation factor, which will produce errors in the least significant bits
uint256 extendedAmount =
_calculateInflationaryBalance(_convertToExtended(_demurragedAmount), day(block.timestamp));
uint256 inflationaryAmount = convertDemurrageToInflationaryValue(_demurragedAmount, day(block.timestamp));
// here ensure total supply does not overflow
_extendedTotalSupply += extendedAmount;
_totalSupply += inflationaryAmount;
unchecked {
_extendedAccuracyBalances[_owner] += extendedAmount;
_balances[_owner] += inflationaryAmount;
}
emit Transfer(address(0), _owner, extendedAmount >> EXTENDED_ACCURACY_BITS);
emit Transfer(address(0), _owner, inflationaryAmount);

return extendedAmount >> EXTENDED_ACCURACY_BITS;
return inflationaryAmount;
}

function _burn(address _owner, uint256 _amount) internal returns (uint256) {
uint256 extendedAmount = _convertToExtended(_amount);
uint256 extendedOwnerBalance = _extendedAccuracyBalances[_owner];
if (extendedOwnerBalance < extendedAmount) {
revert ERC20InsufficientBalance(_owner, _extendedAccuracyBalances[_owner], _amount);
function _burn(address _owner, uint256 _amount) internal {
uint256 ownerBalance = _balances[_owner];
if (ownerBalance < _amount) {
revert ERC20InsufficientBalance(_owner, ownerBalance, _amount);
}
unchecked {
_extendedAccuracyBalances[_owner] = extendedOwnerBalance - extendedAmount;
_balances[_owner] = ownerBalance - _amount;
// rely on total supply tracking complete sum of balances
_extendedTotalSupply -= extendedAmount;
_totalSupply -= _amount;
}
emit Transfer(_owner, address(0), _amount);

return extendedAmount;
}
}
5 changes: 2 additions & 3 deletions src/lift/InflationaryCircles.sol
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,10 @@ contract InflationaryCircles is MasterCopyNonUpgradable, ERC20InflationaryBalanc
// External functions

function unwrap(uint256 _amount) external {
uint256 extendedAmount = _burn(msg.sender, _amount);
_burn(msg.sender, _amount);
// calculate demurraged amount in extended accuracy representation
// then discard garbage bits by shifting right
uint256 demurragedAmount =
convertInflationaryToDemurrageValue(extendedAmount, day(block.timestamp)) >> EXTENDED_ACCURACY_BITS;
uint256 demurragedAmount = convertInflationaryToDemurrageValue(_amount, day(block.timestamp));

hub.safeTransferFrom(address(this), msg.sender, toTokenId(avatar), demurragedAmount, "");

Expand Down

0 comments on commit 188cbb7

Please sign in to comment.