@@ -551,8 +551,10 @@ contract KyberNetwork is WithdrawableNoModifiers, Utils5, IKyberNetwork, Reentra
551
551
IERC20 src ,
552
552
IERC20 dest ,
553
553
address payable destAddress ,
554
- TradeData memory tradeData ,
555
- uint256 expectedDestAmount
554
+ ReservesData memory reservesData ,
555
+ uint256 expectedDestAmount ,
556
+ uint256 srcDecimals ,
557
+ uint256 destDecimals
556
558
) internal virtual returns (bool ) {
557
559
558
560
if (src == dest) {
@@ -564,25 +566,15 @@ contract KyberNetwork is WithdrawableNoModifiers, Utils5, IKyberNetwork, Reentra
564
566
return true ;
565
567
}
566
568
567
- ReservesData memory reservesData = (src == ETH_TOKEN_ADDRESS)
568
- ? tradeData.ethToToken
569
- : tradeData.tokenToEth;
570
- uint256 callValue;
571
-
572
569
for (uint256 i = 0 ; i < reservesData.addresses.length ; i++ ) {
573
- callValue = (src == ETH_TOKEN_ADDRESS) ? reservesData.srcAmounts[i] : 0 ;
574
-
575
- // reserve sends tokens/eth to network. network sends it to destination
576
- require (
577
- reservesData.addresses[i].trade {value: callValue}(
578
- src,
579
- reservesData.srcAmounts[i],
580
- dest,
581
- address (this ),
582
- reservesData.rates[i],
583
- true
584
- ),
585
- "trade failed "
570
+ tradeAndVerifyNetworkBalance (
571
+ reservesData.addresses[i],
572
+ src,
573
+ reservesData.srcAmounts[i],
574
+ dest,
575
+ reservesData.rates[i],
576
+ srcDecimals,
577
+ destDecimals
586
578
);
587
579
}
588
580
@@ -594,6 +586,76 @@ contract KyberNetwork is WithdrawableNoModifiers, Utils5, IKyberNetwork, Reentra
594
586
return true ;
595
587
}
596
588
589
+ /// @dev call trade from reserve and verify balances
590
+ /// return actual dest amount received from reserve
591
+ /// @param reserve reserve address to trade with
592
+ /// @param src src token of the trade
593
+ /// @param srcAmount amount of src token to trade
594
+ /// @param dest dest token of the trade
595
+ /// @param conversionRate conversion rate of the trade
596
+ /// @param srcDecimals src token decimals
597
+ /// @param destDecimals dest token decimals
598
+ function tradeAndVerifyNetworkBalance (
599
+ IKyberReserve reserve ,
600
+ IERC20 src ,
601
+ uint256 srcAmount ,
602
+ IERC20 dest ,
603
+ uint256 conversionRate ,
604
+ uint256 srcDecimals ,
605
+ uint256 destDecimals
606
+ ) internal
607
+ {
608
+ uint256 destBalanceBefore = getBalance (dest, address (this ));
609
+
610
+ uint256 srcBalanceBefore;
611
+ uint256 callValue;
612
+
613
+ if (src == ETH_TOKEN_ADDRESS) {
614
+ srcBalanceBefore = 0 ; // no need to verify src balance
615
+ callValue = srcAmount;
616
+ } else {
617
+ srcBalanceBefore = getBalance (src, address (this ));
618
+ callValue = 0 ;
619
+ }
620
+
621
+ // reserve sends tokens/eth to network. network sends it to destination
622
+ uint256 expectedDestAmount = calcDstQty (
623
+ srcAmount,
624
+ srcDecimals,
625
+ destDecimals,
626
+ conversionRate
627
+ );
628
+
629
+ require (
630
+ reserve.trade {value: callValue}(
631
+ src,
632
+ srcAmount,
633
+ dest,
634
+ address (this ),
635
+ conversionRate,
636
+ true
637
+ ),
638
+ "trade failed "
639
+ );
640
+
641
+ uint256 balanceAfter;
642
+ if (src != ETH_TOKEN_ADDRESS) {
643
+ // verify src balance only if it is not ETH
644
+ balanceAfter = getBalance (src, address (this ));
645
+ // verify correct src amount is taken
646
+ if (srcBalanceBefore >= balanceAfter && srcBalanceBefore - balanceAfter > srcAmount) {
647
+ revert ("reserve takes high amount " );
648
+ }
649
+ }
650
+ // verify correct dest amount is received
651
+ balanceAfter = getBalance (dest, address (this ));
652
+ if (balanceAfter < destBalanceBefore || balanceAfter - destBalanceBefore < expectedDestAmount) {
653
+ revert ("reserve returns low amount " );
654
+ }
655
+ }
656
+
657
+ /* solhint-disable function-max-lines */
658
+ // Most of the lines here are functions calls spread over multiple lines. We find this function readable enough
597
659
/// @notice Use token address ETH_TOKEN_ADDRESS for ether
598
660
/// @dev Trade API for kyber network
599
661
/// @param tradeData Main trade data object for trade info to be stored
@@ -630,8 +692,10 @@ contract KyberNetwork is WithdrawableNoModifiers, Utils5, IKyberNetwork, Reentra
630
692
tradeData.input.src,
631
693
ETH_TOKEN_ADDRESS,
632
694
address (this ),
633
- tradeData,
634
- tradeData.tradeWei
695
+ tradeData.tokenToEth,
696
+ tradeData.tradeWei,
697
+ tradeData.tokenToEth.decimals,
698
+ ETH_DECIMALS
635
699
)
636
700
); // tradeData.tradeWei (expectedDestAmount) not used if destAddress == address(this)
637
701
@@ -641,8 +705,10 @@ contract KyberNetwork is WithdrawableNoModifiers, Utils5, IKyberNetwork, Reentra
641
705
ETH_TOKEN_ADDRESS,
642
706
tradeData.input.dest,
643
707
tradeData.input.destAddress,
644
- tradeData,
645
- destAmount
708
+ tradeData.ethToToken,
709
+ destAmount,
710
+ ETH_DECIMALS,
711
+ tradeData.ethToToken.decimals
646
712
)
647
713
);
648
714
@@ -748,7 +814,7 @@ contract KyberNetwork is WithdrawableNoModifiers, Utils5, IKyberNetwork, Reentra
748
814
view
749
815
returns (uint256 destAmount , uint256 rateWithNetworkFee )
750
816
{
751
- // token to ether: find best reserve match and calculate wei amount
817
+ // token to ether: find best reserves match and calculate wei amount
752
818
tradeData.tradeWei = calcDestQtyAndMatchReserves (
753
819
tradeData.input.src,
754
820
ETH_TOKEN_ADDRESS,
@@ -762,18 +828,17 @@ contract KyberNetwork is WithdrawableNoModifiers, Utils5, IKyberNetwork, Reentra
762
828
return (0 , 0 );
763
829
}
764
830
765
- // platform fee
831
+ // calculate fees
766
832
tradeData.platformFeeWei = (tradeData.tradeWei * tradeData.input.platformFeeBps) / BPS;
767
833
tradeData.networkFeeWei =
768
834
(((tradeData.tradeWei * tradeData.networkFeeBps) / BPS) * tradeData.feeAccountedBps) /
769
835
BPS;
770
- // set networkFeeWei in stack. since we set it again after full flow done.
771
836
require (
772
837
tradeData.tradeWei >= (tradeData.networkFeeWei + tradeData.platformFeeWei),
773
838
"fees exceed trade "
774
839
);
775
840
776
- // ether to token: find best reserve match and calculate trade dest amount
841
+ // ether to token: find best reserves match and calculate trade dest amount
777
842
uint256 actualSrcWei = tradeData.tradeWei -
778
843
tradeData.networkFeeWei -
779
844
tradeData.platformFeeWei;
@@ -1172,8 +1237,7 @@ contract KyberNetwork is WithdrawableNoModifiers, Utils5, IKyberNetwork, Reentra
1172
1237
);
1173
1238
if (newSrcAmounts[i] > currentSrcAmount) {
1174
1239
// revert back to use current src amounts
1175
- newSrcAmount = srcAmount;
1176
- return newSrcAmount;
1240
+ return srcAmount;
1177
1241
}
1178
1242
1179
1243
newSrcAmount += newSrcAmounts[i];
0 commit comments