Skip to content

Commit

Permalink
⚡ 📥 Local ENS
Browse files Browse the repository at this point in the history
  • Loading branch information
z0r0z committed Feb 14, 2024
1 parent bff556d commit b2caa9c
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 33 deletions.
29 changes: 14 additions & 15 deletions .gas-snapshot
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
IETest:testBalanceInERC20() (gas: 62613)
IETest:testBalanceInETH() (gas: 53716)
IETest:testCommandSendERC0() (gas: 114314)
IETest:testCommandSendETH() (gas: 80786)
IETest:testCommandSendUSDC() (gas: 147022)
IETest:testCommandSwapDAI() (gas: 101117)
IETest:testCommandSwapUSDC() (gas: 157110)
IETest:testDeploy() (gas: 2148156)
IETest:testENSNameFromENSHelper() (gas: 29103)
IETest:testENSNameOwnership() (gas: 109286)
IETest:testBalanceInERC20() (gas: 49321)
IETest:testBalanceInETH() (gas: 40402)
IETest:testCommandSendERC0() (gas: 103061)
IETest:testCommandSendETH() (gas: 69533)
IETest:testCommandSendUSDC() (gas: 135769)
IETest:testCommandSwapDAI() (gas: 102069)
IETest:testCommandSwapUSDC() (gas: 157072)
IETest:testDeploy() (gas: 2433818)
IETest:testENSNameOwnership() (gas: 84123)
IETest:testIENameSetting() (gas: 8187)
IETest:testPreviewCommandSendDecimals() (gas: 111612)
IETest:testPreviewCommandSendUSDC() (gas: 77435)
IETest:testPreviewSend() (gas: 54713)
IETest:testPreviewSendCommand() (gas: 66584)
IETest:testSendETH() (gas: 70967)
IETest:testPreviewCommandSendDecimals() (gas: 92090)
IETest:testPreviewCommandSendUSDC() (gas: 66160)
IETest:testPreviewSend() (gas: 42680)
IETest:testPreviewSendCommand() (gas: 54618)
IETest:testSendETH() (gas: 59713)
IETest:testTotalSupply() (gas: 14871)
92 changes: 82 additions & 10 deletions src/IE.sol
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,14 @@ contract IE {
bytes signature;
}

/// =========================== ENUMS =========================== ///

/// @dev ENSAsciiNormalizer rules.
enum Rule {
DISALLOWED,
VALID
}

/// ========================= CONSTANTS ========================= ///

/// @dev The governing DAO address.
Expand All @@ -94,9 +102,6 @@ contract IE {
/// @dev The Maker DAO USD stablecoin address.
address internal constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;

/// @dev ENS name normalizer contract.
IENSHelper internal constant ENS_HELPER = IENSHelper(0x4A5cae3EC0b144330cf1a6CeAD187D8F6B891758);

/// @dev ENS fallback registry contract.
IENSHelper internal constant ENS_REGISTRY =
IENSHelper(0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e);
Expand Down Expand Up @@ -124,11 +129,26 @@ contract IE {
/// @dev DAO-governed token address naming.
mapping(string name => address) public tokens;

/// @dev Each index in idnamap refers to an ascii code point.
/// If idnamap[char] > 2, char maps to a valid ascii character.
/// Otherwise, idna[char] returns Rule.DISALLOWED or Rule.VALID.
/// Modified from ENSAsciiNormalizer deployed by royalfork.eth
/// (0x4A5cae3EC0b144330cf1a6CeAD187D8F6B891758).
bytes1[] internal _idnamap;

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

/// @dev Constructs
/// this implementation.
constructor() payable {}
/// @dev Constructs this IE with `asciimap`.
constructor(bytes memory asciimap) payable {
unchecked {
for (uint256 i; i != asciimap.length; i += 2) {
bytes1 r = asciimap[i + 1];
for (uint8 j; j != uint8(asciimap[i]); ++j) {
_idnamap.push(r);
}
}
}
}

/// ====================== COMMAND PREVIEW ====================== ///

Expand Down Expand Up @@ -318,7 +338,7 @@ contract IE {
: tokenIn.safeTransferFrom(payer, msg.sender, zeroForOne ? amount0Delta : amount1Delta);
}

/// @dev Computes the create2 address for given token pair. Starts mid fee.
/// @dev Computes the create2 address for given token pair. Starts mid.
function _computePoolAddress(address tokenA, address tokenB, uint24 fee)
internal
view
Expand All @@ -338,7 +358,7 @@ contract IE {
mstore(0x35, 0) // Restore the overwritten
}
if (pool.code.length != 0) return (pool, zeroForOne);
else return _computePoolAddress(tokenA, tokenB, 500);
else return _computePoolAddress(tokenA, tokenB, 500); // Low fee.
}

/// ================== BALANCE & SUPPLY HELPERS ================== ///
Expand Down Expand Up @@ -391,11 +411,63 @@ contract IE {
virtual
returns (address owner, address receiver, bytes32 node)
{
(owner, node) = ENS_HELPER.owner(string(abi.encodePacked(name, ".eth")));
(owner, node) = _owner(string(abi.encodePacked(name, ".eth")));
if (IENSHelper(owner) == ENS_WRAPPER) owner = ENS_WRAPPER.ownerOf(uint256(node));
receiver = IENSHelper(ENS_REGISTRY.resolver(node)).addr(node); // Fails on misname.
}

/// @dev Resolves an ENS domain owner.
function _owner(string memory domain)
internal
view
virtual
returns (address domainOwner, bytes32 node)
{
(, node) = _namehash(domain);
return (ENS_REGISTRY.owner(node), node);
}

/// @dev Computes an ENS domain namehash.
function _namehash(string memory domain)
internal
view
virtual
returns (string memory normalized, bytes32 node)
{
// Process labels (in reverse order for namehash).
uint256 i = bytes(domain).length;
uint256 lastDot = i;
unchecked {
for (; i != 0; --i) {
bytes1 c = bytes(domain)[i - 1];
if (c == ".") {
node = keccak256(abi.encodePacked(node, _labelhash(domain, i, lastDot)));
lastDot = i - 1;
continue;
}
require(c < 0x80);
bytes1 r = _idnamap[uint8(c)];
require(uint8(r) != uint8(Rule.DISALLOWED));
if (uint8(r) > 1) {
bytes(domain)[i - 1] = r;
}
}
}
return (domain, keccak256(abi.encodePacked(node, _labelhash(domain, i, lastDot))));
}

/// @dev Computes an ENS domain labelhash given its start and end.
function _labelhash(string memory domain, uint256 start, uint256 end)
internal
pure
virtual
returns (bytes32 hash)
{
assembly ("memory-safe") {
hash := keccak256(add(add(domain, 0x20), start), sub(end, start))
}
}

/// ========================= GOVERNANCE ========================= ///

/// @dev Sets a public `name` tag for a given `token` address. Governed by DAO.
Expand Down Expand Up @@ -527,9 +599,9 @@ interface IExecutor {
/// @dev ENS name resolution helper contracts interface.
interface IENSHelper {
function addr(bytes32) external view returns (address);
function owner(bytes32) external view returns (address);
function ownerOf(uint256) external view returns (address);
function resolver(bytes32) external view returns (address);
function owner(string calldata) external view returns (address, bytes32);
}

/// @dev Simple Uniswap V3 swapping interface.
Expand Down
18 changes: 10 additions & 8 deletions test/IE.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,14 @@ contract IETest is Test {
address internal constant USDC_WHALE = 0xD6153F5af5679a75cC85D8974463545181f48772;
address internal constant DAI_WHALE = 0x075e72a5eDf65F0A5f44699c7654C1a76941Ddc8;

bytes internal constant ASCII_MAP =
hex"2d00020101000a010700016101620163016401650166016701680169016a016b016c016d016e016f0170017101720173017401750176017701780179017a06001a010500";

IE internal ie; // Intents Engine.

function setUp() public payable {
vm.createSelectFork(vm.rpcUrl("main")); // Ethereum mainnet fork.
ie = new IE();
ie = new IE(ASCII_MAP);
vm.prank(DAO);
ie.setName(ETH, "ETH");
vm.prank(DAO);
Expand Down Expand Up @@ -57,7 +60,7 @@ contract IETest is Test {
}

function testDeploy() public payable {
new IE();
new IE(ASCII_MAP);
}

function testENSNameOwnership() public payable {
Expand All @@ -69,12 +72,6 @@ contract IETest is Test {
assertEq(receiver, NANI_DOT_ETH);
}

function testENSNameFromENSHelper() public payable {
(address result,) =
IENSHelper(0x4A5cae3EC0b144330cf1a6CeAD187D8F6B891758).owner("vitalik.eth");
assertEq(result, VITALIK_DOT_ETH);
}

function testPreviewSendCommand() public payable {
string memory command = "send vitalik 20 dai";
(address to, uint256 amount, address asset,,) = ie.previewCommand(command);
Expand Down Expand Up @@ -175,6 +172,11 @@ contract IETest is Test {
assertEq(Z0R0Z_DOT_ETH.balance, zBal + 1 ether);
}

/*function testCommandETH() public payable {
vm.prank(VITALIK_DOT_ETH);
ie.command{value: 10 ether}("swap 10 eth for dai");
}*/

function testCommandSwapDAI() public payable {
vm.prank(DAI_WHALE);
IERC20(DAI).approve(address(ie), 100 ether);
Expand Down

0 comments on commit b2caa9c

Please sign in to comment.