Reflection Token: How it works and Why SafeMoon pumped high once

0xCryptoQuant
8 min readOct 26, 2023

Impossible Triangles and Trade-offs

Embarking on the fascinating journey into the world of DeFi often commences with a deep dive into the Bitcoin whitepaper. It’s there that I encounter the intriguing ‘impossible triangle,’ a concept that eloquently illustrates the intricate balance between decentralization, security, and scalability.

At its core, decentralization represents a bedrock principle of the crypto space, allowing individuals the freedom to become validators within the network. However, when we consider the fundamental requirements of a public blockchain, security emerges as the linchpin. It’s the non-negotiable foundation upon which everything else rests, making it a cornerstone of the impossible triangle.

In contrast, scalability often takes a backseat in the equation, making way for the other two critical components. This is why you might notice that transaction fees on Bitcoin or gas fees on Ethereum surpass those of traditional payment methods, despite perceivable speed or bandwidth disadvantage.

Yet, even within the constraints of scalability, ingenious solutions have sprung forth. They enable complex token transactions with the utmost efficiency, all while maintaining elegant smart contract designs. One particularly captivating creation to emerge post-DeFi Summer’s fervor is the introduction of reflection tokens — a unique and creative approach to supporting tokenomics and ensuring DeFi’s continued success.

What reflection token is

Imagine every time a token holder makes a transfer or swap, a small percentage of that token is deducted from their balance. What happens next is where the magic begins — a portion of this token is returned to the liquidity pool, while the rest is distributed among fellow holders. The underlying calculation and code logic might seem straightforward in the world of traditional finance. However, in the realm of cryptocurrencies, introducing a tax on every transfer, combined with recalculating the balance of every address involved, could result in shockingly high gas consumption.

Enter the resourceful concept of reflection tokens, an open-source innovation pioneered by the renowned SafeMoon project. Not only does it provide valuable insights, but it also serves as a source of inspiration for enhancing gas efficiency and streamlining the entire process to its utmost simplicity.

Code Explanation

Account Management Variables

First two variables are the most important ones, for respectively saving reflective token account balance mapping and original token account balance. Whether or not an account can receive rewards is also manged by variables among them.

  mapping(address => uint256) private _rOwned; // reflective token owned
mapping(address => uint256) private _tOwned; // token owned

mapping(address => mapping(address => uint256)) private _allowances;

mapping(address => bool) private _isExcludedFromFee; // Account which pay or not pay transaction fee

mapping(address => bool) private _isExcluded; // Accounts which will receive rewards or not (if true: (account is exclude from receiving reward), if false: account is not excluded: hence can receive rewards)

address[] private _excluded; // Accounts which does not receive rewards

Arithmetic Variables

The only thing worth mention for variables below is that reflective token amount is exactly certain times of original token amount.

  uint256 private constant MAX = ~uint256(0); // 2^256 -1 = 1.15792089237316195423570985008687907853269984665640564039457584007913129639935×10⁷⁷
uint256 private _tTotal = 1000000000 * 10**6 * 10**9; // 10^9 * 10^6 * 10^9 = 10^24 = One Septillion
uint256 private _rTotal = (MAX - (MAX % _tTotal)); // 1.15792089237316195423570985008687907853269984665640564×10^77

/// @notice Total fees collected through transfers
uint256 private _tFeeTotal;

string private _name = "Reflecive Token";
string private _symbol = "RFT";
uint8 private _decimals = 9;

uint256 public _taxFee = 5;
uint256 private _previousTaxFee = _taxFee;

uint256 public _liquidityFee = 5;
uint256 private _previousLiquidityFee = _liquidityFee;

IUniswapV2Router02 public immutable uniswapV2Router;
address public immutable uniswapV2Pair;

bool inSwapAndLiquify;
bool public swapAndLiquifyEnabled = true;

uint256 public _maxTxAmount = 5000000 * 10**6 * 10**9; // 50^21
uint256 private numTokensSellToAddToLiquidity = 500000 * 10**6 * 10**9; // 50^20

Balance Calculation

there are two main calcultions for balance calculation. The first one is we use a rate value to divide reflective token amount of an address to calculate its original token balance.

balanceOf(address) = rAmount / currentRate

The second one is about how the rate is calculated. So far, we know that denominator of the formula is a fixed number which is equal to toal amount of original token (aka. _tTotal).

Till now, you can have a rough understanding that when the total supply of reflective tokens decreases, the rate also decreases. When such a situation occurs during token swaps or transfers, the rate decreases. Combining this with the first formula, the original token quantity in the user’s account will increase.

currentRate = rSupply / tSupply

 function balanceOf(address account) public view override returns (uint256) {
if (_isExcluded[account]) return _tOwned[account];

return tokenFromReflection(_rOwned[account]);
}

/// @notice This function calculate how many tokens per reflection
/// @dev In the starting reflection value should be larger or you can get an idea
/// by running {reflectionFromToken} to get reflection per token
function tokenFromReflection(uint256 rAmount) public view returns (uint256) {
require(rAmount <= _rTotal, "Amount must be less than total reflections");

uint256 currentRate = _getRate(); // 1.15792089237316195423570985008687907853269984665640564×10⁵³
return rAmount.div(currentRate); // (2 * 10^53) / (1.15792089237316195423570985008687907853269984665640564×10⁵³) = 1
}

/// @notice Calculate current rate of token.
/// @return Current rate by simple formula (reflection remaining supply / total remaining supply)
function _getRate() private view returns (uint256) {
(uint256 rSupply, uint256 tSupply) = _getCurrentSupply(); // (1.1579×10^53 , 10^24)
return rSupply.div(tSupply); // 1.15792089237316195423570985008687907853269984665640564×10⁵³
}

Token Transfer

In typical condition of token transfer which means neither sender nor recipient is not excluded from rewards distribution, the implementation code is function “_transferStandard”.

  /// @notice This function get reflection & transfer values (including reflection & transfer fees).
/// subtract sender reflection amount from his reflection balance
/// add reflection transfer amount to the recipient transfer balance
/// smart contract take the liquidity and reflect the both fees
/// @param {sender} sender address
/// @param {recipient} recipient address
/// @param {tAmount} transfering amount
function _transferStandard(
address sender,
address recipient,
uint256 tAmount
) private {
(
uint256 rAmount,
uint256 rTransferAmount,
uint256 rFee,
uint256 tTransferAmount,
uint256 tFee,
uint256 tLiquidity
) = _getValues(tAmount);

_rOwned[sender] = _rOwned[sender].sub(rAmount);
_rOwned[recipient] = _rOwned[recipient].add(rTransferAmount);
_takeLiquidity(tLiquidity);
_reflectFee(rFee, tFee);
emit Transfer(sender, recipient, tTransferAmount);
}

Before updating account balance, you need to calculate transfer, tax fee and liquidity fee values for both reflective and original token. The original token values are calculated at first and then reflective token values are computed via multiplying rates to them.

Reflective token balance of sender and recipient is updated by substracting or adding values got from “_getValues”.

  /// @notice Calculate Transfer and Reflection values
/// @param {tAmount} Total transfer amount
/// @return rAmount Reflection amount
/// @return rTransferAmount Reflection transfer amount
/// @return rFee reflection fees
/// @return tTransferAmount transfer amount
/// @return tFee transfer fee
/// @return tLiquidity transfer liquidity
function _getValues(uint256 tAmount)
private
view
returns (
uint256,
uint256,
uint256,
uint256,
uint256,
uint256
)
{
// 100000000000 (tAmount)
(uint256 tTransferAmount, uint256 tFee, uint256 tLiquidity) = _getTValues(tAmount); // (90000000000 , 5000000000 , 5000000000 )
(uint256 rAmount, uint256 rTransferAmount, uint256 rFee) = _getRValues(
tAmount,
tFee,
tLiquidity,
_getRate()
);
//(9.26336713898529563388567880069503262826159877325124512×10⁶³ , 5.7896044618658097711785492504343953926634992332820282×10⁶² , 5.7896044618658097711785492504343953926634992332820282×10⁶²)
return (rAmount, rTransferAmount, rFee, tTransferAmount, tFee, tLiquidity);
}

The liquidity fee amount is recorded in the reflective token balance of the token contract. If the contract is excluded from receiving rewards then original token balance is required to be refreshed. And when the exclusion state is reversed to false, the original token balance will be set as 0.

  /// @notice This function will increase the reflection and transfer balance of smart contract by rLiquidity and tLiquidity
/// @param {tLiquidity} It is calculated by calculateLiquidityFee() function
function _takeLiquidity(uint256 tLiquidity) private {
uint256 currentRate = _getRate();
uint256 rLiquidity = tLiquidity.mul(currentRate);
_rOwned[address(this)] = _rOwned[address(this)].add(rLiquidity);
if (_isExcluded[address(this)]) _tOwned[address(this)] = _tOwned[address(this)].add(tLiquidity);
}

With tax fee being cutting from total reflective token amount, the exchange rate between reflective token and original token is going up which means the same quantity reflective token can be converted into a greater quantity of original token.

  /// @notice Reflect fees, subtract rFee from _rTotal and add tFee in _tFeeTotal
/// @param {rFee} reflection fee
/// @param {tFee} transfer fee
function _reflectFee(uint256 rFee, uint256 tFee) private {
_rTotal = _rTotal.sub(rFee);
_tFeeTotal = _tFeeTotal.add(tFee);
}

The logic of code implementation under different token transfer conditions is largely similar to function “_transferStandard”.

  /// @notice This function perform fees checks and then according to the sender and recipient
/// excluded flags transfer given amount to the recipient.
/// @param {sender} sender address
/// @param {recipient} recipient address
/// @param {amount} transfering amount
/// @param {takeFee} flag either charge a fees or not
function _tokenTransfer(
address sender,
address recipient,
uint256 amount,
bool takeFee
) private {
// if take fee is false, removeAllFee() is called to set fees(taxFee and liquidityFee) to zero
if (!takeFee) removeAllFee();

if (_isExcluded[sender] && !_isExcluded[recipient]) {
_transferFromExcluded(sender, recipient, amount);
} else if (!_isExcluded[sender] && _isExcluded[recipient]) {
_transferToExcluded(sender, recipient, amount);
} else if (!_isExcluded[sender] && !_isExcluded[recipient]) {
// The _transferStandard function is called if both sender and recipient are not excluded from receiving rewards (they can both receive rewards)
_transferStandard(sender, recipient, amount);
} else if (_isExcluded[sender] && _isExcluded[recipient]) {
_transferBothExcluded(sender, recipient, amount);
} else {
_transferStandard(sender, recipient, amount);
}

if (!takeFee) restoreAllFee();
}

Other Elements for SafeMoon’s pump

Timing: A Well-Placed Bet

It all began in November 2021 when I delved into the verification time of the token proxy smart contract. Back then, the world of on-chain memes was still riding high, with the shadow of subsequent challenges like SBF’s scandal and LUNA’s death spiral yet to loom. Retail investors were eagerly seeking the next Dogecoin or meme stock sensation, much like the WallStreetBets frenzy. Against this backdrop, Bitcoin and Ethereum were hitting record highs, saturating the market with liquidity. It was precisely at this juncture that SafeMoon made its debut, capitalizing on the perfect storm.

Market Operations: The Visionary Leadership

At the helm of SafeMoon was John Karony, a visionary leader adept in program management and technical writing. He steered the project with a series of well-crafted market strategies, setting a new standard in reliability for retail investors. While many projects at the time raised concerns by distributing a significant share of tokens to ventures or core members, SafeMoon took a different path. It not only burned all developer tokens upon launch but also embraced fair and transparent IEO and IDO mechanisms. The tokenomics and the innovative reflection scheme were executed with precision. Trillions of coins were systematically removed from circulation to maintain a scarce supply, creating a tidal wave of enthusiasm in the market.

Death Spiral

zero fundamentals and usage

Amid the frenzy of price pumping fueled by FOMO, SafeMoon’s market value once soared to over $1 billion. However, it has since plummeted by more than 90% of its market value, and its low trading volume now gives it the appearance of a dormant project. The results indicate a lack of utility or incentives for diamond hands if the price trend shifts from an uptrend to a downtrend.

Moreover, the project’s inactivity in both development and the trading market suggests that the team hasn’t shown much commitment to maintaining or enhancing the token’s utility.

Is it a case of bad tokenomics?

It resembles ponzinomics more than just poor tokenomics. These two concepts share some similarities. In a Ponzi scheme, you earn dividends from new participants joining the scheme, while in shit coins, you earn reflections from others buying in.

However, there is a notable drawback: holders are obligated to pay taxes when they engage in trading. This signals that the project’s primary focus is on inflating the price, but such a strategy is generally short-lived.

Source

market research

algorithm discussion

code explanation video

reddit discussion

--

--

0xCryptoQuant

truth miner ⛏️ - diving into the depths of digital gold 🤿. twitter@0xCryptoQuant