|
| 1 | +// SPDX-License-Identifier: MIT |
| 2 | +pragma solidity ^0.8.0; |
| 3 | + |
| 4 | +import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; |
| 5 | +import { LibErrorHandler } from "../LibErrorHandler.sol"; |
| 6 | + |
| 7 | +using { toAmount } for Gas global; |
| 8 | + |
| 9 | +enum Gas { |
| 10 | + Strictly, |
| 11 | + NoGriefing, |
| 12 | + ForwardAll, |
| 13 | + NoStorageWrite |
| 14 | +} |
| 15 | + |
| 16 | +/// @dev see: https://github.com/axieinfinity/ronin-dpos-contracts/pull/195 |
| 17 | +uint256 constant GAS_STIPEND_STRICT = 0; |
| 18 | + |
| 19 | +/// @dev Suggested gas stipend for contract receiving NATIVE |
| 20 | +/// that disallows any storage writes. |
| 21 | +uint256 constant GAS_STIPEND_NO_STORAGE_WRITES = 2_300; |
| 22 | + |
| 23 | +/// @dev Suggested gas stipend for contract receiving NATIVE to perform a few |
| 24 | +/// storage reads and writes, but low enough to prevent griefing. |
| 25 | +/// Multiply by a small constant (e.g. 2), if needed. |
| 26 | +uint256 constant GAS_STIPEND_NO_GRIEF = 100_000; |
| 27 | + |
| 28 | +function toAmount(Gas gas) view returns (uint256) { |
| 29 | + if (gas == Gas.ForwardAll) return gasleft(); |
| 30 | + if (gas == Gas.NoGriefing) return GAS_STIPEND_NO_GRIEF; |
| 31 | + if (gas == Gas.NoStorageWrite) return GAS_STIPEND_NO_STORAGE_WRITES; |
| 32 | + return GAS_STIPEND_STRICT; |
| 33 | +} |
| 34 | + |
| 35 | +/** |
| 36 | + * @title NativeTransferHelper |
| 37 | + */ |
| 38 | +library LibNativeTransfer { |
| 39 | + using Strings for *; |
| 40 | + using LibErrorHandler for bool; |
| 41 | + |
| 42 | + /** |
| 43 | + * @dev Transfers Native Coin and wraps result for the method caller to a recipient. |
| 44 | + */ |
| 45 | + function safeTransfer(address to, uint256 value, Gas gas) internal { |
| 46 | + (bool success, bytes memory returnOrRevertData) = trySendValue(to, value, gas.toAmount()); |
| 47 | + success.handleRevert(bytes4(0x0), returnOrRevertData); |
| 48 | + } |
| 49 | + |
| 50 | + /** |
| 51 | + * @dev Unsafe send `amount` Native to the address `to`. If the sender's balance is insufficient, |
| 52 | + * the call does not revert. |
| 53 | + * |
| 54 | + * Note: |
| 55 | + * - Does not assert whether the balance of sender is sufficient. |
| 56 | + * - Does not assert whether the recipient accepts NATIVE. |
| 57 | + * - Consider using `ReentrancyGuard` before calling this function. |
| 58 | + * |
| 59 | + */ |
| 60 | + function trySendValue(address to, uint256 value, uint256 gasAmount) |
| 61 | + internal |
| 62 | + returns (bool success, bytes memory returnOrRevertData) |
| 63 | + { |
| 64 | + (success, returnOrRevertData) = to.call{ value: value, gas: gasAmount }(""); |
| 65 | + } |
| 66 | +} |
0 commit comments