Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make .eth token ID change when fuses are burned #2

Merged
merged 11 commits into from
Aug 15, 2024
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
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