Skip to content

Commit

Permalink
Merge pull request #2 from ensdomains/immutable-tokens
Browse files Browse the repository at this point in the history
Make .eth token ID change when fuses are burned
  • Loading branch information
Arachnid authored Aug 15, 2024
2 parents 5849def + e1bae67 commit e4858f3
Show file tree
Hide file tree
Showing 23 changed files with 664 additions and 256 deletions.
28 changes: 28 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: CI

on:
push:
branches: [main]
pull_request:

jobs:
test:
name: Contract tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: "recursive"

- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1

- name: Use Bun 1.1.16
uses: oven-sh/setup-bun@v1
with:
bun-version: 1.1.16

- run: bun install --frozen-lockfile

- name: Run tests
run: bun --filter contracts test
Binary file modified bun.lockb
Binary file not shown.
19 changes: 19 additions & 0 deletions contracts/hardhat.config.cts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { HardhatUserConfig } from "hardhat/config";

import "@nomicfoundation/hardhat-foundry";
import "@nomicfoundation/hardhat-verify";
import "@nomicfoundation/hardhat-viem";
import "./tasks/esm_fix.cjs";

import("@ensdomains/hardhat-chai-matchers-viem");

const config = {
solidity: {
version: "0.8.25",
settings: {
evmVersion: "cancun",
},
},
} satisfies HardhatUserConfig;

export default config;
15 changes: 0 additions & 15 deletions contracts/hardhat.config.ts

This file was deleted.

13 changes: 9 additions & 4 deletions contracts/package.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
{
"name": "contracts",
"module": "index.ts",
"type": "module",
"scripts": {
"test:hardhat": "hardhat test",
"test:forge": "echo \"Skipping forge test for now since there are no tests...\"",
"compile:hardhat": "NODE_OPTIONS='--experimental-loader ts-node/esm/transpile-only' hardhat compile",
"test:hardhat": "NODE_OPTIONS='--experimental-loader ts-node/esm/transpile-only' hardhat test",
"test:forge": "forge test",
"test": "bun run test:forge && bun run test:hardhat"
},
"devDependencies": {
"@ensdomains/hardhat-chai-matchers-viem": "^0.0.7",
"@nomicfoundation/hardhat-foundry": "^1.1.1",
"@nomicfoundation/hardhat-toolbox": "^5.0.0",
"@nomicfoundation/hardhat-toolbox-viem": "^3.0.0",
"@nomicfoundation/hardhat-viem": "^2.0.0",
"@types/bun": "latest",
"@vitest/expect": "^1.6.0",
"chai": "^5.1.1",
"hardhat": "^2.22.2",
"ts-node": "^10.9.2",
"viem": "^2.9.12"
},
"peerDependencies": {
Expand Down
54 changes: 28 additions & 26 deletions contracts/src/registry/BaseRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,69 +14,71 @@ import {IRegistryDatastore} from "./IRegistryDatastore.sol";
import {IRegistry} from "./IRegistry.sol";

abstract contract BaseRegistry is IRegistry, ERC1155Singleton {
error AccessDenied(string label, address owner, address caller);
error InvalidSubregistryFlags(string label, uint96 flags, uint96 expected);
error InvalidResolverFlags(string label, uint96 flags, uint96 expected);
error AccessDenied(uint256 tokenId, address owner, address caller);
error InvalidSubregistryFlags(uint256 tokenId, uint96 flags, uint96 expected);
error InvalidResolverFlags(uint256 tokenId, uint96 flags, uint96 expected);

IRegistryDatastore public datastore;

constructor(IRegistryDatastore _datastore) {
datastore = _datastore;
}

modifier onlyTokenOwner(string calldata label) {
uint256 tokenId = uint256(keccak256(bytes(label)));
modifier onlyTokenOwner(uint256 tokenId) {
address owner = ownerOf(tokenId);
if (owner != msg.sender) {
revert AccessDenied(label, owner, msg.sender);
revert AccessDenied(tokenId, owner, msg.sender);
}
_;
}

modifier withSubregistryFlags(string calldata label, uint96 mask, uint96 expected) {
(, uint96 flags) = datastore.getSubregistry(uint256(keccak256(bytes(label))));
modifier withSubregistryFlags(uint256 tokenId, uint96 mask, uint96 expected) {
(, uint96 flags) = datastore.getSubregistry(tokenId);
if (flags & mask != expected) {
revert InvalidSubregistryFlags(label, flags & mask, expected);
revert InvalidSubregistryFlags(tokenId, flags & mask, expected);
}
_;
}

modifier withResolverFlags(string calldata label, uint96 mask, uint96 expected) {
(, uint96 flags) = datastore.getResolver(uint256(keccak256(bytes(label))));
modifier withResolverFlags(uint256 tokenId, uint96 mask, uint96 expected) {
(, uint96 flags) = datastore.getResolver(tokenId);
if (flags & mask != expected) {
revert InvalidResolverFlags(label, flags & mask, expected);
revert InvalidResolverFlags(tokenId, flags & mask, expected);
}
_;
}

/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC1155Singleton, IERC165) returns (bool) {
return
interfaceId == type(IERC1155).interfaceId ||
interfaceId == type(IERC1155MetadataURI).interfaceId ||
interfaceId == type(IRegistry).interfaceId ||
super.supportsInterface(interfaceId);
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(ERC1155Singleton, IERC165)
returns (bool)
{
return interfaceId == type(IERC1155).interfaceId || interfaceId == type(IERC1155MetadataURI).interfaceId
|| interfaceId == type(IRegistry).interfaceId || super.supportsInterface(interfaceId);
}

function _mint(string calldata label, address owner, IRegistry registry, uint96 flags) internal {
uint256 tokenId = uint256(keccak256(bytes(label)));
function _mint(uint256 tokenId, address owner, IRegistry registry, uint96 flags) internal {
_mint(owner, tokenId, 1, "");
datastore.setSubregistry(tokenId, address(registry), flags);
emit NewSubname(label);
}

/***********************
/**
*
* IRegistry functions *
***********************/

*
*/

/**
* @dev Fetches the registry for a subdomain of the current registry.
* @param label The label to resolve.
* @return The address of the registry for this subdomain, or `address(0)` if none exists.
*/
function getSubregistry(string calldata label) external virtual view returns (IRegistry) {
function getSubregistry(string calldata label) external view virtual returns (IRegistry) {
(address subregistry,) = datastore.getSubregistry(uint256(keccak256(bytes(label))));
return IRegistry(subregistry);
}
Expand All @@ -86,7 +88,7 @@ abstract contract BaseRegistry is IRegistry, ERC1155Singleton {
* @param label The label to fetch a resolver for.
* @return resolver The address of a resolver responsible for this name, or `address(0)` if none exists.
*/
function getResolver(string calldata label) external virtual view returns (address resolver) {
function getResolver(string calldata label) external view virtual returns (address resolver) {
(resolver,) = datastore.getResolver(uint256(keccak256(bytes(label))));
}
}
51 changes: 24 additions & 27 deletions contracts/src/registry/ERC1155Singleton.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,8 @@ abstract contract ERC1155Singleton is Context, ERC165, IERC1155Singleton, IERC11
using Arrays for uint256[];
using Arrays for address[];

event Approval(
address indexed owner,
address indexed approved,
uint256 indexed tokenId
);

event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

mapping(uint256 id => address) private _owners;

mapping(address account => mapping(address operator => bool)) private _operatorApprovals;
Expand All @@ -37,18 +33,16 @@ abstract contract ERC1155Singleton is Context, ERC165, IERC1155Singleton, IERC11
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return
interfaceId == type(IERC1155).interfaceId ||
interfaceId == type(IERC1155Singleton).interfaceId ||
interfaceId == type(IERC1155MetadataURI).interfaceId ||
super.supportsInterface(interfaceId);
return interfaceId == type(IERC1155).interfaceId || interfaceId == type(IERC1155Singleton).interfaceId
|| interfaceId == type(IERC1155MetadataURI).interfaceId || super.supportsInterface(interfaceId);
}

/**************************************************************************
/**
*
* ERC1155 methods
*************************************************************************/

function uri(uint256 /* id */) public view virtual returns (string memory);
*
*/
function uri(uint256 /* id */ ) public view virtual returns (string memory);

/**
* @dev See {IERC1155-balanceOf}.
Expand All @@ -64,10 +58,12 @@ abstract contract ERC1155Singleton is Context, ERC165, IERC1155Singleton, IERC11
*
* - `accounts` and `ids` must have the same length.
*/
function balanceOfBatch(
address[] memory accounts,
uint256[] memory ids
) public view virtual returns (uint256[] memory) {
function balanceOfBatch(address[] memory accounts, uint256[] memory ids)
public
view
virtual
returns (uint256[] memory)
{
if (accounts.length != ids.length) {
revert ERC1155InvalidArrayLength(ids.length, accounts.length);
}
Expand Down Expand Up @@ -148,11 +144,11 @@ abstract contract ERC1155Singleton is Context, ERC165, IERC1155Singleton, IERC11
uint256 id = ids.unsafeMemoryAccess(i);
uint256 value = values.unsafeMemoryAccess(i);

if(value > 0) {
if (value > 0) {
address owner = _owners[id];
if(owner != from) {
if (owner != from) {
revert ERC1155InsufficientBalance(from, 0, value, id);
} else if(value > 1) {
} else if (value > 1) {
revert ERC1155InsufficientBalance(from, 1, value, id);
}
_owners[id] = to;
Expand Down Expand Up @@ -320,7 +316,7 @@ abstract contract ERC1155Singleton is Context, ERC165, IERC1155Singleton, IERC11
}
_updateWithAcceptanceCheck(from, address(0), ids, values, "");
}

/**
* @dev Approve `operator` to operate on all of `owner` tokens
*
Expand All @@ -341,10 +337,11 @@ abstract contract ERC1155Singleton is Context, ERC165, IERC1155Singleton, IERC11
/**
* @dev Creates an array in memory with only one value for each of the elements provided.
*/
function _asSingletonArrays(
uint256 element1,
uint256 element2
) private pure returns (uint256[] memory array1, uint256[] memory array2) {
function _asSingletonArrays(uint256 element1, uint256 element2)
private
pure
returns (uint256[] memory array1, uint256[] memory array2)
{
/// @solidity memory-safe-assembly
assembly {
// Load the free memory pointer
Expand Down
Loading

0 comments on commit e4858f3

Please sign in to comment.