• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Tribally-Games / arcade-contracts / 18929517494

30 Oct 2025 04:05AM UTC coverage: 95.724% (-1.5%) from 97.241%
18929517494

push

github

hiddentao
refactor: use custom error reverts for quote calculations

Replace return values with CalculatedAmountOut custom error for quote
operations across adapters and gateway. This improves gas efficiency for
view-only quote simulations by using reverts instead of state-changing
returns.

- Add CalculatedAmountOut error to IDexSwapAdapter interface and LibErrors
- Update DummyDexAdapter and UniversalSwapAdapter getQuote implementations
- Update GatewayFacet calculateUsdc to use custom error
- Add parseCalculatedAmountOut utility in gateway-utils for error parsing
- Update test scripts to handle new quote mechanism
- Improve deployment script verification flow with skip option
- Update deployment addresses for Base and Ronin networks
- Add warning note about non-USDC deposits on Base

54 of 63 branches covered (85.71%)

Branch coverage included in aggregate %.

13 of 17 new or added lines in 4 files covered. (76.47%)

237 of 241 relevant lines covered (98.34%)

18.67 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.72
/src/facets/GatewayFacet.sol
1
// SPDX-License-Identifier: AGPL-3.0
2
pragma solidity 0.8.24;
3

4
import { AppStorage, LibAppStorage } from "src/libs/LibAppStorage.sol";
5
import { LibErrors } from "src/libs/LibErrors.sol";
6
import { LibAuth } from "src/libs/LibAuth.sol";
7
import { LibUsdcToken } from "src/libs/LibUsdcToken.sol";
8
import { LibToken } from "src/libs/LibToken.sol";
9
import { AuthSignature } from "src/shared/Structs.sol";
10
import { ReentrancyGuard } from "src/shared/ReentrancyGuard.sol";
11
import { IDexSwapAdapter } from "src/interfaces/IDexSwapAdapter.sol";
12
import { IERC20 } from "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
13
import { SafeERC20 } from "lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
14

15
contract GatewayFacet is ReentrancyGuard {
16
  using SafeERC20 for IERC20;
17

18
  event TriballyGatewayDeposit(
19
    address indexed user,
20
    address indexed depositToken,
21
    uint256 depositAmount,
22
    uint256 usdcAmount
23
  );
24

25
  event TriballyGatewayWithdraw(address user, uint amount);
26

27
  function gatewayPoolBalance() external view returns (uint) {
21✔
28
    return LibAppStorage.diamondStorage().gatewayPoolBalance;
21✔
29
  }
30

31
  function deposit(
24✔
32
    address _user,
33
    address _token,
34
    uint256 _amount,
35
    uint256 _minUsdcAmount,
36
    bytes calldata _swapData
37
  ) external payable nonReentrant {
38
    if (_user == address(0)) revert LibErrors.InvalidInputs();
24✔
39

40
    AppStorage storage s = LibAppStorage.diamondStorage();
23✔
41

42
    bool isNative = _token == address(0);
23✔
43

44
    if (isNative) {
6✔
45
      if (msg.value != _amount) {
6✔
46
        revert LibErrors.InvalidInputs();
1✔
47
      }
48
    } else {
49
      LibToken.transferFrom(_token, msg.sender, _amount);
17✔
50
    }
51

52
    uint256 usdcAmount;
22✔
53

54
    if (_token == s.usdcToken) {
22✔
55
      usdcAmount = _amount;
14✔
56
    } else {
57
      if (!isNative) {
8✔
58
        IERC20(_token).forceApprove(s.swapAdapter, _amount);
3✔
59
      }
60

61
      uint256 usdcBalanceBefore = IERC20(s.usdcToken).balanceOf(address(this));
8✔
62

63
      usdcAmount = IDexSwapAdapter(s.swapAdapter).swap{ value: isNative ? _amount : 0 }(
8✔
64
        _token,
65
        _amount,
66
        _minUsdcAmount,
67
        _swapData
68
      );
69

70
      if (!isNative) {
7✔
71
        IERC20(_token).forceApprove(s.swapAdapter, 0);
3✔
72
      }
73

74
      uint256 usdcBalanceAfter = IERC20(s.usdcToken).balanceOf(address(this));
7✔
75
      uint256 usdcReceived = usdcBalanceAfter - usdcBalanceBefore;
7✔
76

77
      if (usdcReceived != usdcAmount) {
7✔
78
        revert LibErrors.InvalidSwapOutput();
1✔
79
      }
80

81
      if (usdcAmount < _minUsdcAmount) {
6✔
82
        revert LibErrors.InsufficientUsdcReceived(usdcAmount, _minUsdcAmount);
1✔
83
      }
84
    }
85

86
    s.gatewayPoolBalance += usdcAmount;
19✔
87

88
    emit TriballyGatewayDeposit(_user, _token, _amount, usdcAmount);
19✔
89
  }
90

91
  /**
92
   * This should be called via eth_call as it is designed to revert.
93
   * The swap adapter's getQuote will revert with CalculatedAmountOut.
94
   * @param _token The token to calculate the USDC amount for.
95
   * @param _amount The amount of token to calculate the USDC amount for.
96
   * @param _swapData The swap data for the adapter.
97
   */
98
  function calculateUsdc(address _token, uint256 _amount, bytes calldata _swapData) external payable {
10✔
99
    AppStorage storage s = LibAppStorage.diamondStorage();
10✔
100

101
    if (_token == s.usdcToken) {
10✔
102
      revert LibErrors.CalculatedAmountOut(_amount);
1✔
103
    }
104

105
    bool isNative = _token == address(0);
9✔
106

107
    if (!isNative) {
9✔
108
      LibToken.transferFrom(_token, msg.sender, _amount);
1✔
109
      IERC20(_token).forceApprove(s.swapAdapter, _amount);
1✔
110
    }
111

112
    IDexSwapAdapter(s.swapAdapter).getQuote{ value: msg.value }(_token, _amount, _swapData);
9✔
113

114
    if (!isNative) {
1!
NEW
115
      IERC20(_token).forceApprove(s.swapAdapter, 0);
×
116
    }
117

118
    revert LibErrors.InvalidSwapAdapter();
1✔
119
  }
120

121
  function withdraw(address _user, uint _amount,  AuthSignature calldata _sig) external nonReentrant {
9✔
122
    AppStorage storage s = LibAppStorage.diamondStorage();
9✔
123

124
    LibAuth.assertValidSignature(msg.sender, s.signer, _sig, abi.encodePacked(_user, _amount));
9✔
125

126
    if (s.gatewayPoolBalance < _amount) {
5✔
127
      revert LibErrors.InsufficientBalanceError();
1✔
128
    }
129

130
    s.gatewayPoolBalance -= _amount;
4✔
131

132
    LibUsdcToken.transferTo(_user, _amount);
4✔
133

134
    emit TriballyGatewayWithdraw(_user, _amount);
4✔
135
  }
136
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc