Skip to content

Commit

Permalink
🥢 ~~ Nit addr resolve
Browse files Browse the repository at this point in the history
  • Loading branch information
z0r0z committed Feb 21, 2024
1 parent e54d721 commit f66a22e
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 90 deletions.
36 changes: 19 additions & 17 deletions .gas-snapshot
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
IETest:testCommandDepositETH() (gas: 188523)
IETest:testCommandSendETH() (gas: 71778)
IETest:testCommandSendETHRawAddr() (gas: 99310)
IETest:testCommandStakeETH() (gas: 184104)
IETest:testCommandSwapDAI() (gas: 169036)
IETest:testCommandSwapETH() (gas: 165652)
IETest:testCommandSwapForETH() (gas: 172373)
IETest:testCommandSwapUSDC() (gas: 203905)
IETest:testCommandSwapUSDCForWBTC() (gas: 235400)
IETest:testCommandUnstakeETH() (gas: 312227)
IETest:testCommandWithdrawETH() (gas: 314737)
IETest:testDeploy() (gas: 2783837)
IETest:testENSNameOwnership() (gas: 44454)
IETest:testIENameSetting() (gas: 8208)
IETest:testPreviewCommandSendDecimals() (gas: 100925)
IETest:testPreviewCommandSendUSDC() (gas: 74278)
IETest:testPreviewSend() (gas: 53627)
IETest:testPreviewSendCommand() (gas: 64515)
IETest:testCommandSendETHRawAddr() (gas: 66606)
IETest:testCommandStakeETH() (gas: 184060)
IETest:testCommandSwapDAI() (gas: 160386)
IETest:testCommandSwapETH() (gas: 164553)
IETest:testCommandSwapForETH() (gas: 163723)
IETest:testCommandSwapUSDC() (gas: 203643)
IETest:testCommandSwapUSDCForWBTC() (gas: 205482)
IETest:testCommandUnstakeETH() (gas: 312292)
IETest:testCommandWithdrawETH() (gas: 314715)
IETest:testDeploy() (gas: 2922278)
IETest:testENSNameOwnership() (gas: 44499)
IETest:testIENameSetting() (gas: 8186)
IETest:testPreviewCommandSendDecimals() (gas: 100903)
IETest:testPreviewCommandSendUSDC() (gas: 74256)
IETest:testPreviewSend() (gas: 53679)
IETest:testPreviewSendCommand() (gas: 64493)
IETest:testPreviewSendCommandRawAddr() (gas: 59337)
IETest:testPreviewSendRawAddr() (gas: 29412)
NAMITest:testFailRegister() (gas: 9392)
NAMITest:testRegister() (gas: 55668)
NAMITest:testRegister() (gas: 55699)
81 changes: 47 additions & 34 deletions src/IE.sol
Original file line number Diff line number Diff line change
Expand Up @@ -210,30 +210,7 @@ contract IE {
if (_token == address(0)) _token = tokens[token]; // Check storage.
bool isETH = _token == ETH; // Memo whether the token is ETH or not.
(, _to,) = whatIsTheAddressOf(to); // Fetch receiver address from ENS.
_amount = _stringToUint(amount, isETH ? 18 : _token.readDecimals());
if (!isETH) callData = abi.encodeCall(IToken.transfer, (_to, _amount));
executeCallData =
abi.encodeCall(IExecutor.execute, (isETH ? _to : _token, isETH ? _amount : 0, callData));
}

/// @dev Previews a `send` command like `previewSend` but includes raw `to`.
function previewSend(address to, string memory amount, string memory token)
public
view
virtual
returns (
address _to,
uint256 _amount,
address _token,
bytes memory callData,
bytes memory executeCallData
)
{
_to = to; // Flip it back. This just helps maintain formatted output.
_token = _returnTokenConstant(bytes32(bytes(token))); // Check constant.
if (_token == address(0)) _token = tokens[token]; // Check storage.
bool isETH = _token == ETH; // Memo whether the token is ETH or not.
_amount = _stringToUint(amount, isETH ? 18 : _token.readDecimals());
_amount = _toUint(amount, isETH ? 18 : _token.readDecimals());
if (!isETH) callData = abi.encodeCall(IToken.transfer, (_to, _amount));
executeCallData =
abi.encodeCall(IExecutor.execute, (isETH ? _to : _token, isETH ? _amount : 0, callData));
Expand All @@ -255,9 +232,8 @@ contract IE {
if (_tokenIn == address(0)) _tokenIn = tokens[tokenIn];
_tokenOut = _returnTokenConstant(bytes32(bytes(tokenOut)));
if (_tokenOut == address(0)) _tokenOut = tokens[tokenOut];
_amountIn = _stringToUint(amountIn, _tokenIn == ETH ? 18 : _tokenIn.readDecimals());
_amountOut =
_stringToUint(amountOutMinimum, _tokenOut == ETH ? 18 : _tokenOut.readDecimals());
_amountIn = _toUint(amountIn, _tokenIn == ETH ? 18 : _tokenIn.readDecimals());
_amountOut = _toUint(amountOutMinimum, _tokenOut == ETH ? 18 : _tokenOut.readDecimals());
}

/// @dev Checks ERC4337 userOp against the output of the command intent.
Expand Down Expand Up @@ -333,9 +309,9 @@ contract IE {
if (_token == address(0)) _token = tokens[token];
(, address _to,) = whatIsTheAddressOf(to);
if (_token == ETH) {
_to.safeTransferETH(_stringToUint(amount, 18));
_to.safeTransferETH(_toUint(amount, 18));
} else {
_token.safeTransferFrom(msg.sender, _to, _stringToUint(amount, _token.readDecimals()));
_token.safeTransferFrom(msg.sender, _to, _toUint(amount, _token.readDecimals()));
}
}

Expand All @@ -357,7 +333,7 @@ contract IE {
info.ETHOut = info.tokenOut == ETH;
if (info.ETHOut) info.tokenOut = WETH;

info.amountIn = _stringToUint(amountIn, info.ETHIn ? 18 : info.tokenIn.readDecimals());
info.amountIn = _toUint(amountIn, info.ETHIn ? 18 : info.tokenIn.readDecimals());
if (info.amountIn >= 1 << 255) revert Overflow();
(address pool, bool zeroForOne) = _computePoolAddress(info.tokenIn, info.tokenOut);
(int256 amount0, int256 amount1) = ISwapRouter(pool).swap(
Expand All @@ -369,7 +345,7 @@ contract IE {
);
if (
uint256(-(zeroForOne ? amount1 : amount0))
< _stringToUint(amountOutMinimum, info.ETHOut ? 18 : info.tokenOut.readDecimals())
< _toUint(amountOutMinimum, info.ETHOut ? 18 : info.tokenOut.readDecimals())
) revert InsufficientSwap();
}

Expand Down Expand Up @@ -551,8 +527,9 @@ contract IE {
virtual
returns (address owner, address receiver, bytes32 node)
{
if (bytes(name).length == 20) {
receiver = address(bytes20(bytes(name)));
// If address length, convert.
if (bytes(name).length == 42) {
receiver = _toAddress(name);
} else {
(owner, receiver, node) = INames(NAMI).whatIsTheAddressOf(name);
}
Expand Down Expand Up @@ -688,7 +665,7 @@ contract IE {
}

/// @dev Convert string to decimalized numerical value.
function _stringToUint(string memory s, uint8 decimals)
function _toUint(string memory s, uint8 decimals)
internal
pure
virtual
Expand Down Expand Up @@ -718,6 +695,42 @@ contract IE {
}
}
}

/// @dev Converts a hexadecimal string to its `address` representation.
/// Modified from Stack (https://ethereum.stackexchange.com/a/156916)
function _toAddress(string memory s) public pure virtual returns (address addr) {
bytes memory _bytes = _hexStringToAddress(s);
if (_bytes.length < 21) revert InvalidSyntax();
assembly ("memory-safe") {
addr := div(mload(add(add(_bytes, 0x20), 1)), 0x1000000000000000000000000)
}
}

/// @dev Converts a hexadecimal string into its bytes representation.
function _hexStringToAddress(string memory s) internal pure virtual returns (bytes memory r) {
unchecked {
bytes memory ss = bytes(s);
require(ss.length % 2 == 0); // Length must be even.
r = new bytes(ss.length / 2);
for (uint256 i; i != ss.length / 2; ++i) {
r[i] =
bytes1(_fromHexChar(uint8(ss[2 * i])) * 16 + _fromHexChar(uint8(ss[2 * i + 1])));
}
}
}

/// @dev Converts a single hexadecimal character into its numerical value.
function _fromHexChar(uint8 c) internal pure virtual returns (uint8 result) {
unchecked {
if (bytes1(c) >= bytes1("0") && bytes1(c) <= bytes1("9")) return c - uint8(bytes1("0"));
if (bytes1(c) >= bytes1("a") && bytes1(c) <= bytes1("f")) {
return 10 + c - uint8(bytes1("a"));
}
if (bytes1(c) >= bytes1("A") && bytes1(c) <= bytes1("F")) {
return 10 + c - uint8(bytes1("A"));
}
}
}
}

/// @dev Simple token transfer interface.
Expand Down
46 changes: 7 additions & 39 deletions src/NAMI.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.19;

/// @title NANI ARBITRUM MESSAGE INVENTORY (NAMI)
/// @title NANI ARBITRUM MAGIC INVOICE (NAMI)
/// @notice A contract for managing ENS domain name ownership and resolution on Arbitrum L2.
/// @dev Provides functions for registering names, verifying ownership, and resolving addresses.
/// @author nani.eth (https://github.com/NaniDAO/ie)
Expand Down Expand Up @@ -64,8 +64,8 @@ contract NAMI {
/// (0x4A5cae3EC0b144330cf1a6CeAD187D8F6B891758).
bytes1[] internal _idnamap;

/// @dev Internal mapping of registered name owners.
mapping(bytes32 => address) internal _owners;
/// @dev Internal mapping of registered node owners.
mapping(bytes32 node => address) internal _owners;

/// ======================== CONSTRUCTOR ======================== ///

Expand Down Expand Up @@ -150,15 +150,15 @@ contract NAMI {
/// ====================== OWNERSHIP LOGIC ====================== ///

/// @dev Returns the registered owner of a given ENS L1 node. Must be bridged.
/// note: Alternatively, NAMI provides subdomains issued under nani.eth node.
/// note: Alternatively, NAMI provides subdomains issued under `nani.eth` node.
function owner(bytes32 _node) public view virtual returns (address _owner) {
_owner = _owners[_node];
if (!isOwner(_owner, _node)) revert Unregistered();
if (_owner == address(0) || !isOwner(_owner, _node)) revert Unregistered();
}

/// @dev Checks if an address is the owner of a given ENS L1 node represented as `l2Token`.
/// note: NAMI operates under the assumption that the proper owner-receiver holds majority.
function isOwner(address _owner, bytes32 _node) public view virtual returns (bool result) {
function isOwner(address _owner, bytes32 _node) public view virtual returns (bool) {
(, address l2Token) = predictDeterministicAddresses(_node);
return IToken(l2Token).balanceOf(_owner) > (IToken(l2Token).totalSupply() / 2);
}
Expand Down Expand Up @@ -249,41 +249,9 @@ contract NAMI {
)
);
}

/// ===================== STRING OPERATIONS ===================== ///

/// @dev Returns copy of string in lowercase.
/// Modified from Solady LibString `toCase`.
function _lowercase(string memory subject)
internal
pure
virtual
returns (string memory result)
{
assembly ("memory-safe") {
let length := mload(subject)
if length {
result := add(mload(0x40), 0x20)
subject := add(subject, 1)
let flags := shl(add(70, shl(5, 0)), 0x3ffffff)
let w := not(0)
for { let o := length } 1 {} {
o := add(o, w)
let b := and(0xff, mload(add(subject, o)))
mstore8(add(result, o), xor(b, and(shr(b, flags), 0x20)))
if iszero(o) { break }
}
result := mload(0x40)
mstore(result, length) // Store the length.
let last := add(add(result, 0x20), length)
mstore(last, 0) // Zeroize the slot after the string.
mstore(0x40, add(last, 0x20)) // Allocate the memory.
}
}
}
}

/// @dev Simple token balance and supply interface.
/// @dev Simple token balance & supply interface.
interface IToken {
function totalSupply() external view returns (uint256);
function balanceOf(address) external view returns (uint256);
Expand Down

0 comments on commit f66a22e

Please sign in to comment.