这是indexloc提供的服务,不要输入任何密码
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: test

on: workflow_dispatch
on: push

env:
FOUNDRY_PROFILE: ci
Expand Down Expand Up @@ -29,6 +29,5 @@ jobs:
id: build

- name: Run Forge tests
run: |
forge test -vvv
run: forge test -vvvv --summary --detailed --gas-report
id: test
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,11 @@ Tiny web3 protocols and applications.
The aim is to keep it simple, quick to implement and interesting to learn Solidity.

Inspired by [lil-web3](https://github.com/m1guelpf/lil-web3) by [Miguel Piedrafita](https://twitter.com/m1guelpf).

## Table of contents

- [Tiny ENS](#tiny-ens)

## Tiny ENS

Map human-readable names like 'vitalik.eth' to machine-readable identifiers such as Ethereum addresses like '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045' and support the reverse resolution.
3 changes: 3 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,8 @@
src = "src"
out = "out"
libs = ["lib"]
remappings = [
'@forge-std/=lib/forge-std/src/',
]

# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options
65 changes: 65 additions & 0 deletions src/TinyENS.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

/// @notice Interface for TinyENS.
interface ITinyENS {
/// @notice Register a new ENS name and link it to an address.
/// @param name The ENS name to register.
function register(string memory name) external;

/// @notice Update the ENS name linked to an address.
/// @param newName The new ENS name.
function update(string memory newName) external;

/// @notice Resolve the address associated with a given ENS name.
/// @param name The ENS name to resolve.
/// @return The address associated with the ENS name.
function resolve(string memory name) external view returns (address);

/// @notice Reverse resolve an address to its associated ENS name.
/// @param targetAddress The target address to reverse resolve.
/// @return The ENS name associated with the address.
function reverse(address targetAddress) external view returns (string memory);
}

/// @title Tiny Ethereum Name Service
/// @author leovct
/// @notice Map human-readable names like 'vitalik.eth' to machine-readable identifiers such as
/// Ethereum addresses like '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045' and support the reverse
/// resolution.
contract TinyENS is ITinyENS {
/// @notice Thrown when trying to register a name already registered.
error AlreadyRegistered();

/// @notice Map ENS names to addresses.
mapping(string => address) private registry;

/// @notice Map addresses to ENS names.
mapping(address => string) private reverseRegistry;

modifier notRegistered(string memory name) {
if (registry[name] != address(0)) revert AlreadyRegistered();
_;
}

function register(string memory name) public notRegistered(name) {
registry[name] = msg.sender;
reverseRegistry[msg.sender] = name;
}

function update(string memory newName) external notRegistered(newName) {
// Unlink the old name and the address.
string memory oldName = reverseRegistry[msg.sender];
registry[oldName] = address(0);
// Register the new name.
register(newName);
}

function resolve(string memory name) external view returns (address) {
return registry[name];
}

function reverse(address targetAddress) external view returns (string memory) {
return reverseRegistry[targetAddress];
}
}
80 changes: 80 additions & 0 deletions test/TinyENS.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import '../src/TinyENS.sol';
import '@forge-std/Test.sol';

contract TinyENSTest is Test {
TinyENS private tinyENS;

address private owner = makeAddr('owner');
address private alice = makeAddr('alice');
address private bob = makeAddr('bob');

function setUp() public {
vm.startPrank(owner);
tinyENS = new TinyENS();
console2.log('TinyENS deployed');
vm.stopPrank();
}

function testRegisterNewName() public {
vm.startPrank(alice);
tinyENS.register('alice.eth');
vm.stopPrank();

assertEq(tinyENS.resolve('alice.eth'), alice);
assertEq(tinyENS.reverse(alice), 'alice.eth');
console2.log('Alice registed alice.eth');
}

function testRegisterAlreadyRegisteredName() public {
vm.startPrank(alice);
tinyENS.register('alice.eth');
assertEq(tinyENS.resolve('alice.eth'), alice);
assertEq(tinyENS.reverse(alice), 'alice.eth');
console2.log('Alice registed alice.eth');

console2.log('Bob tries to register alice.eth');
vm.startPrank(bob);
vm.expectRevert(TinyENS.AlreadyRegistered.selector);
tinyENS.register('alice.eth');
assertEq(tinyENS.resolve('alice.eth'), alice);
assertEq(tinyENS.reverse(alice), 'alice.eth');
assertEq(tinyENS.reverse(bob), '');
vm.stopPrank();
}

function testUpdateWithNewName() public {
vm.startPrank(alice);
tinyENS.register('alice.eth');
assertEq(tinyENS.resolve('alice.eth'), alice);
assertEq(tinyENS.reverse(alice), 'alice.eth');
console2.log('Alice registed alice.eth');

tinyENS.register('alice22.eth');
assertEq(tinyENS.resolve('alice22.eth'), alice);
assertEq(tinyENS.reverse(alice), 'alice22.eth');
console2.log('Alice updated its name to alice22.eth');
vm.stopPrank();
}

function testUpdateWithAlreadyRegisteredName() public {
vm.startPrank(alice);
tinyENS.register('alice.eth');
console2.log('Alice registed alice.eth');

vm.startPrank(bob);
tinyENS.register('bob.eth');
console2.log('Bob registed bob.eth');

console2.log('Bob tries to update its name to alice.eth');
vm.expectRevert(TinyENS.AlreadyRegistered.selector);
tinyENS.update('alice.eth');
assertEq(tinyENS.resolve('alice.eth'), alice);
assertEq(tinyENS.reverse(alice), 'alice.eth');
assertEq(tinyENS.resolve('bob.eth'), bob);
assertEq(tinyENS.reverse(bob), 'bob.eth');
vm.stopPrank();
}
}