github.com/status-im/status-go@v1.1.0/services/wallet/router/pathprocessor/processor_swap_paraswap_test.go (about)

     1  package pathprocessor
     2  
     3  import (
     4  	"errors"
     5  	"math/big"
     6  	"testing"
     7  
     8  	"github.com/ethereum/go-ethereum/common"
     9  
    10  	gomock "github.com/golang/mock/gomock"
    11  
    12  	"github.com/status-im/status-go/params"
    13  	"github.com/status-im/status-go/services/wallet/bigint"
    14  	walletCommon "github.com/status-im/status-go/services/wallet/common"
    15  	"github.com/status-im/status-go/services/wallet/thirdparty/paraswap"
    16  	mock_paraswap "github.com/status-im/status-go/services/wallet/thirdparty/paraswap/mock"
    17  	"github.com/status-im/status-go/services/wallet/token"
    18  
    19  	"github.com/stretchr/testify/require"
    20  )
    21  
    22  func TestParaswapWithPartnerFee(t *testing.T) {
    23  	testPriceRoute := &paraswap.Route{
    24  		GasCost:            &bigint.BigInt{Int: big.NewInt(500)},
    25  		SrcAmount:          &bigint.BigInt{Int: big.NewInt(1000)},
    26  		SrcTokenAddress:    common.HexToAddress("0x123"),
    27  		SrcTokenDecimals:   18,
    28  		DestAmount:         &bigint.BigInt{Int: big.NewInt(2000)},
    29  		DestTokenAddress:   common.HexToAddress("0x465"),
    30  		DestTokenDecimals:  6,
    31  		Side:               paraswap.SellSide,
    32  		ContractAddress:    common.HexToAddress("0x789"),
    33  		TokenTransferProxy: common.HexToAddress("0xabc"),
    34  	}
    35  
    36  	processor := NewSwapParaswapProcessor(nil, nil, nil)
    37  
    38  	fromToken := token.Token{
    39  		Symbol: EthSymbol,
    40  	}
    41  	toToken := token.Token{
    42  		Symbol: UsdcSymbol,
    43  	}
    44  	chainIDs := []uint64{walletCommon.EthereumMainnet, walletCommon.ArbitrumMainnet, walletCommon.OptimismMainnet, walletCommon.UnknownChainID}
    45  
    46  	for _, chainID := range chainIDs {
    47  		key := makeKey(chainID, chainID, fromToken.Symbol, toToken.Symbol)
    48  		processor.priceRoute.Store(key, testPriceRoute)
    49  
    50  		testInputParams := ProcessorInputParams{
    51  			FromChain: &params.Network{ChainID: chainID},
    52  			ToChain:   &params.Network{ChainID: chainID},
    53  			FromToken: &fromToken,
    54  			ToToken:   &toToken,
    55  		}
    56  
    57  		partnerAddress, partnerFeePcnt := getPartnerAddressAndFeePcnt(chainID)
    58  
    59  		if partnerAddress != walletCommon.ZeroAddress {
    60  			require.Greater(t, partnerFeePcnt, 0.0)
    61  
    62  			expectedFee := uint64(float64(testPriceRoute.DestAmount.Uint64()) * partnerFeePcnt / 100.0)
    63  			expectedDestAmount := testPriceRoute.DestAmount.Uint64() - expectedFee
    64  
    65  			amountOut, err := processor.CalculateAmountOut(testInputParams)
    66  			require.NoError(t, err)
    67  			require.NotNil(t, amountOut)
    68  			require.InEpsilon(t, expectedDestAmount, amountOut.Uint64(), 2.0)
    69  		} else {
    70  			require.Equal(t, 0.0, partnerFeePcnt)
    71  
    72  			amountOut, err := processor.CalculateAmountOut(testInputParams)
    73  			require.NoError(t, err)
    74  			require.NotNil(t, amountOut)
    75  			require.Equal(t, testPriceRoute.DestAmount.Uint64(), amountOut.Uint64())
    76  		}
    77  
    78  		// Check contract address
    79  		contractAddress, err := processor.GetContractAddress(testInputParams)
    80  		require.NoError(t, err)
    81  		require.Equal(t, testPriceRoute.TokenTransferProxy, contractAddress)
    82  	}
    83  }
    84  
    85  func expectClientFetchPriceRoute(clientMock *mock_paraswap.MockClientInterface, route paraswap.Route, err error) {
    86  	clientMock.EXPECT().FetchPriceRoute(
    87  		gomock.Any(),
    88  		gomock.Any(),
    89  		gomock.Any(),
    90  		gomock.Any(),
    91  		gomock.Any(),
    92  		gomock.Any(),
    93  		gomock.Any(),
    94  		gomock.Any(),
    95  		gomock.Any(),
    96  	).Return(route, err)
    97  }
    98  
    99  func TestParaswapErrors(t *testing.T) {
   100  	ctrl := gomock.NewController(t)
   101  	defer ctrl.Finish()
   102  
   103  	client := mock_paraswap.NewMockClientInterface(ctrl)
   104  
   105  	processor := NewSwapParaswapProcessor(nil, nil, nil)
   106  	processor.paraswapClient = client
   107  
   108  	fromToken := token.Token{
   109  		Symbol: EthSymbol,
   110  	}
   111  	toToken := token.Token{
   112  		Symbol: UsdcSymbol,
   113  	}
   114  	chainID := walletCommon.EthereumMainnet
   115  
   116  	testInputParams := ProcessorInputParams{
   117  		FromChain: &params.Network{ChainID: chainID},
   118  		ToChain:   &params.Network{ChainID: chainID},
   119  		FromToken: &fromToken,
   120  		ToToken:   &toToken,
   121  	}
   122  
   123  	// Test Errors
   124  	type testCase struct {
   125  		clientError    string
   126  		processorError error
   127  	}
   128  
   129  	testCases := []testCase{
   130  		{"Price Timeout", ErrPriceTimeout},
   131  		{"No routes found with enough liquidity", ErrNotEnoughLiquidity},
   132  		{"ESTIMATED_LOSS_GREATER_THAN_MAX_IMPACT", ErrPriceImpactTooHigh},
   133  	}
   134  
   135  	for _, tc := range testCases {
   136  		expectClientFetchPriceRoute(client, paraswap.Route{}, errors.New(tc.clientError))
   137  		_, err := processor.EstimateGas(testInputParams)
   138  		require.Equal(t, tc.processorError.Error(), err.Error())
   139  	}
   140  }