Skip to content

Commit

Permalink
Merge pull request #34 from axieinfinity/release/v0.1.0
Browse files Browse the repository at this point in the history
chore: merge from branch 'release/v0.1.0'
  • Loading branch information
TuDo1403 authored Dec 11, 2023
2 parents 29686ed + 2388600 commit f177e3b
Show file tree
Hide file tree
Showing 8 changed files with 132 additions and 9 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# smart-contracts-core
# contract-libs

The collections of smart contracts that power the Axie Land Delegation.

Expand Down
6 changes: 0 additions & 6 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,6 @@ ffi = true

# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options

remappings = [
'forge-std/=lib/forge-std/src/',
'ds-test/=lib/forge-std/lib/ds-test/src/',
'@openzeppelin/=lib/openzeppelin-contracts/',
]

solc = '0.8.23'
evm_version = 'istanbul'
use_literal_content = true
Expand Down
2 changes: 1 addition & 1 deletion lib/forge-std
2 changes: 1 addition & 1 deletion lib/openzeppelin-contracts
40 changes: 40 additions & 0 deletions src/LibErrorHandler.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

library LibErrorHandler {
/// @dev Reserves error definition to upload to signature database.
error ExternalCallFailed(bytes4 msgSig, bytes4 callSig);

/// @notice handle low level call revert if call failed,
/// If extcall return empty bytes, reverts with custom error.
/// @param status Status of external call
/// @param callSig function signature of the calldata
/// @param returnOrRevertData bytes result from external call
function handleRevert(bool status, bytes4 callSig, bytes memory returnOrRevertData) internal pure {
// Get the function signature of current context
bytes4 msgSig = msg.sig;
assembly ("memory-safe") {
if iszero(status) {
// Load the length of bytes array
let revertLength := mload(returnOrRevertData)
// Check if length != 0 => revert following reason from external call
if iszero(iszero(revertLength)) {
// Start of revert data bytes. The 0x20 offset is always the same.
revert(add(returnOrRevertData, 0x20), revertLength)
}

// Load free memory pointer
let ptr := mload(0x40)
// Store 4 bytes the function selector of ExternalCallFailed(msg.sig, callSig)
// Equivalent to revert ExternalCallFailed(bytes4,bytes4)
mstore(ptr, 0x49bf4104)
// Store 4 bytes of msgSig parameter in the next slot
mstore(add(ptr, 0x20), msgSig)
// Store 4 bytes of callSig parameter in the next slot
mstore(add(ptr, 0x40), callSig)
// Revert 68 bytes of error starting from 0x1c
revert(add(ptr, 0x1c), 0x44)
}
}
}
}
20 changes: 20 additions & 0 deletions src/math/LibSafeRange.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

library LibSafeRange {
function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
unchecked {
c = a + b;
if (c < a) return type(uint256).max;
}
}

/**
* @dev Returns value of a + b; in case result is larger than upperbound, upperbound is returned.
*/
function addWithUpperbound(uint256 a, uint256 b, uint256 ceil) internal pure returns (uint256 c) {
if (a > ceil || b > ceil) return ceil;
c = add(a, b);
if (c > ceil) return ceil;
}
}
36 changes: 36 additions & 0 deletions src/transfers/LibNativeTransfer.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import { LibErrorHandler } from "../LibErrorHandler.sol";

/**
* @title NativeTransferHelper
*/
library LibNativeTransfer {
using LibErrorHandler for bool;

/**
* @dev Transfers Native Coin and wraps result for the method caller to a recipient.
*/
function transfer(address to, uint256 value, uint256 gasAmount) internal {
(bool success, bytes memory returnOrRevertData) = trySendValue(to, value, gasAmount);
success.handleRevert(bytes4(0x0), returnOrRevertData);
}

/**
* @dev Unsafe send `amount` Native to the address `to`. If the sender's balance is insufficient,
* the call does not revert.
*
* Note:
* - Does not assert whether the balance of sender is sufficient.
* - Does not assert whether the recipient accepts NATIVE.
* - Consider using `ReentrancyGuard` before calling this function.
*
*/
function trySendValue(address to, uint256 value, uint256 gasAmount)
internal
returns (bool success, bytes memory returnOrRevertData)
{
(success, returnOrRevertData) = to.call{ value: value, gas: gasAmount }("");
}
}
33 changes: 33 additions & 0 deletions test/transfers/LibNativeTransfer.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

import { Test } from "forge-std/Test.sol";
import { LibNativeTransfer } from "src/transfers/LibNativeTransfer.sol";

contract LibNativeTransferTest is Test {
function testFork_RevertWhen_TransferNativeToContractWithoutFallback_safeTransfer(
address any,
uint256 amount,
uint256 gas
) external {
vm.deal(any, amount);
vm.expectRevert();
vm.prank(any);
LibNativeTransfer.transfer(address(this), amount, gas);
}

function testConcrete_TransferNative(uint256 gas) external {
LibNativeTransfer.transfer(address(0xBEEF), 1e18, gas);
assertEq(address(0xBEEF).balance, 1e18);
}

function testFork_TransferNativeToRecipient(address recipient, uint256 amount, uint256 gas) external {
// Transferring to msg.sender can fail because it's possible to overflow their ETH balance as it begins non-zero.
if (recipient.code.length > 0 || uint256(uint160(recipient)) <= 18 || recipient == msg.sender) return;

amount = _bound(amount, 0, address(this).balance);
LibNativeTransfer.transfer(recipient, amount, gas);

assertEq(recipient.balance, amount);
}
}

0 comments on commit f177e3b

Please sign in to comment.