I am trying to wrap my head around Swap event (which should be equivalent to ).

Here is an example transaction: 0xd809e359a4037eb5e2617769b93f8b7fa1e708c37019b02933e1845e33c99884

This transaction contains Swap event:

Swap (
  index_topic_1 address sender,
  uint256 amount0In,
  uint256 amount1In,
  uint256 amount0Out,
  uint256 amount1Out,
  index_topic_2 address to

and it has the following values:

sender: 0x10ed43c718714eb63d5aa57b78b54704e256024e
amount0In: 12772329830235
amount1In: 2562091000000000000
amount0Out: 208940457743532637
amount1Out: 0
to: 0x97c2727b8f0584f45f86d2d3dead77e5c74814bc

and this event originates from contract 0xff3dd404afba451328de089424c74685bf0a43c9.

As far as I understand,

In this case,

If I am reading this event correctly, it says that we are trading WBNB 0.2562091 for SafeMoon 208,940,457.


  • BscScan shows that the actual amount transferred is 188,046,411. This can also be seen by looking at the logs, Transfer event.
  • It is not clear what role does amount0In (12772329830235) play in Swap event.

How does one determine by looking at the Swap event that we traded WBNB 0.2562091 for SafeMoon 208,940,457?


Let's use this transaction as an example:


As a benchmark, let's use BoggedFinance data. It says that:

PHX - BNB LP PancakeSwap V2
7,924,800,360.499 PHX + 0.131 BNB
Liquidity Pool Totals
Pool adds $631,122 to total liquidity
PHX pooled: 55,236,876,104,150
BNB pooled: 910
Total LP Tokens: 6,970
KI pooled: 1,314,655,947,122
BNB pooled: 0.000
Total LP Tokens: 2,141.465

It is a swap between these two tokens:

Token0: PHX
Token0.address: 0xb98d864ddcb573567b3a2258c9e5cab58fe7974e
Token1: WBNB
Token1.address: 0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c

Other addresses mentioned in the logs:

Initiator: 0xC5f0Ac8AEd9D12C0645d16aB5892bb09Fc297590
Router (v2): 0x10ed43c718714eb63d5aa57b78b54704e256024e
PHX-WBNB LP: 0x2c3a0aa216cefb8c887716b993c3158f011f967e

BscScan says that the following amounts were transferred:

For 0.1 ($34.01) Wrapped BNB (WBNB)
For 5,314,263,769 PhoenixProtocol (PHX)

i.e. 0.1 WBNB was transferred in exchange for 5,314,263,769 PHX

actual=5,314,263,769 = 5,314,263,769

However, if we were to use Bogged provided quote, the expected amount should be:

0.1 x bnb_phx = 6,064,311,946.1


((expected-actual)/((expected+actual)/2))*100 = 13.18351603551288580585

i.e. We would expect 13.18% more than what we got.

0.2% is a PancakeSwap fee.

The rest must be a combination of slippage and error between when the Bogged values were observed and when the trade took time (it is volatile market afterall).

A comment in the contract states that there is a 10% fee on every transaction, which may account for the difference.

The following events have been recorded:

Address: 0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c
Destination: 0x10ed43c718714eb63d5aa57b78b54704e256024e
Wad: 100000000000000000

This is initiator transferring 0.1 (100000000000000000/10^18) WBNB to Router.

Address: 0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c
Source: 0x10ed43c718714eb63d5aa57b78b54704e256024e
Destination: 0x2c3a0aa216cefb8c887716b993c3158f011f967e
Wad: 100000000000000000

This is Router adding 0.1 WBNB to PHX-WBNB LP.

Address: 0xb98d864ddcb573567b3a2258c9e5cab58fe7974e
Source: 0x2c3a0aa216cefb8c887716b993c3158f011f967e
Destination: 0xc5f0ac8aed9d12c0645d16ab5892bb09fc297590
Wad: 5314263769851279617

This is PHX-WBNB LP sending 5,314,263,769 (5314263769851279617/10^9) to Buyer.

Address: 0x2c3a0aa216cefb8c887716b993c3158f011f967e
Reserve0: 54569750545915728248786
Reserve1: 921958306311444356872

This event indicates that PHX-WBNB LP have been updated.

Address: 0x2c3a0aa216cefb8c887716b993c3158f011f967e
Sender: 0x10ed43c718714eb63d5aa57b78b54704e256024e
Addressee: 0xc5f0ac8aed9d12c0645d16ab5892bb09fc297590
amount0In: 12888802144710313
amount1In: 100000000000000000
amount0Out: 5904737522056977352
amount1Out: 0

This event describes how much was sold (amount0In, amount1In) and how much was received (amount0Out, amount1Out).

What's interesting is that 5904737522056977352 does not align with the actual amount transferred.


i.e. actual amount is 10.52% less than what amount_out says

((actual-amount_out)/((actual+amount_out)/2))*100 = -10.52631580448580946687

There is also the amount_in_0 parameter. 


This equal to 0.2% of the amount_out, which appears to be PancakeSwap fee.

(amount_in_0/amount_out)*100 = 0.21827899973501988968

At the end, amount_out does not account for 10%, which aligns with the advertised contract fee, and it seems that there is no way to get the actual amount transferred just by looking at the Swap event.

It is worth noting that the quote that we calculated using two reserves does not reflect the 10% fee, i.e. The initial expected amount (6,064,311,946) closely aligns with the amount0Out (5,904,737,522).

i.e. Looks like the only way to get the actual amount is by looking at the Transfer events.


PancakePair _swap function:

    // this low-level function should be called from a contract which performs important safety checks
function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external lock {
    require(amount0Out > 0 || amount1Out > 0, 'Pancake: INSUFFICIENT_OUTPUT_AMOUNT');
    (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings
    require(amount0Out < _reserve0 && amount1Out < _reserve1, 'Pancake: INSUFFICIENT_LIQUIDITY');

    uint balance0;
    uint balance1;
    { // scope for _token{0,1}, avoids stack too deep errors
    address _token0 = token0;
    address _token1 = token1;
    require(to != _token0 && to != _token1, 'Pancake: INVALID_TO');
    if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out); // optimistically transfer tokens
    if (amount1Out > 0) _safeTransfer(_token1, to, amount1Out); // optimistically transfer tokens
    if (data.length > 0) IPancakeCallee(to).pancakeCall(msg.sender, amount0Out, amount1Out, data);
    balance0 = IERC20(_token0).balanceOf(address(this));
    balance1 = IERC20(_token1).balanceOf(address(this));
    uint amount0In = balance0 > _reserve0 - amount0Out ? balance0 - (_reserve0 - amount0Out) : 0;
    uint amount1In = balance1 > _reserve1 - amount1Out ? balance1 - (_reserve1 - amount1Out) : 0;
    require(amount0In > 0 || amount1In > 0, 'Pancake: INSUFFICIENT_INPUT_AMOUNT');
    { // scope for reserve{0,1}Adjusted, avoids stack too deep errors
    uint balance0Adjusted = (balance0.mul(10000).sub(amount0In.mul(25)));
    uint balance1Adjusted = (balance1.mul(10000).sub(amount1In.mul(25)));
    require(balance0Adjusted.mul(balance1Adjusted) >= uint(_reserve0).mul(_reserve1).mul(10000**2), 'Pancake: K');

    _update(balance0, balance1, _reserve0, _reserve1);
    emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to);

Safemoon whitepaper:

Safemoon Protocol SafeMoon employs 3 simple functions: Reflection + LP acquisition + Burn In each trade, the transaction is taxed a 10% fee, which is split 2 ways.

  • 5% fee = redistributed to all existing holders
  • 5% fee is split 50/50 half of which is sold by the contract into BNB, while the other half of the SAFEMOON tokens are paired automatically with the previously mentioned BNB and added as a liquidity pair on Pancake Swap.

Amount0Out 208940457743532637 is calculated outside _swap function and sent to _safeTransfer function as a parameter:

if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out); // optimistically transfer tokens

Safemoon contract actually transfers to recipient specified amount of tokens minus 10% (5% tax fee and 5% liquidity fee) 208940457743532637 - 10% = 188046411969179375 and emits Transfer event. Then, PancakePair _swap function emits Swap event with base value of Amount0Out 208940457743532637

Amount0In is greater than zero because Safemoon contract returns part of safemoon tokens as a liquidity pair on Pancake Swap.

uint amount0In = balance0 > _reserve0 - amount0Out ? balance0 - (_reserve0 - amount0Out) : 0;

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.