├── .babelrc ├── public ├── favicon.ico ├── manifest.json └── index.html ├── src ├── frontend │ ├── contractsData │ │ ├── EnsName-address.json │ │ └── EnsName.json │ └── components │ │ ├── logo.png │ │ ├── Loading.js │ │ ├── App.css │ │ ├── Navbar.js │ │ ├── BuyEns.js │ │ ├── ListItem.js │ │ ├── App.js │ │ └── ENSContract.json ├── index.js ├── backend │ ├── scripts │ │ └── deploy.js │ ├── contracts │ │ └── EnsName.sol │ └── test │ │ └── test.js └── serviceWorker.js ├── .env.example ├── hardhat.config.js ├── .gitignore ├── Readme.md └── package.json /.babelrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | { 4 | "presets": [ 5 | "@babel/preset-env" 6 | ] 7 | } -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dappuniversity/ENS-Marketplace/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/frontend/contractsData/EnsName-address.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": "0xC174d0bcD0b20F9723Eec70e931cAd9Db9b51dc0" 3 | } -------------------------------------------------------------------------------- /src/frontend/components/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dappuniversity/ENS-Marketplace/HEAD/src/frontend/components/logo.png -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | ALCHEMY_API_KEY= 2 | INFURA_API_KEY= 3 | 4 | PRIVATE_KEY= 5 | 6 | ETHERSCAN_API_KEY= 7 | 8 | 9 | RINKEBY_RPC= 10 | 11 | POLYGON_MUMBAI_RPC= 12 | 13 | GOERLI_RPC= 14 | 15 | KOVAN_RPC= 16 | 17 | ROPSTEN_RPC= 18 | 19 | 20 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /hardhat.config.js: -------------------------------------------------------------------------------- 1 | require("@nomicfoundation/hardhat-toolbox"); 2 | require('dotenv').config() 3 | 4 | module.exports = { 5 | solidity: "0.8.9", 6 | networks: { 7 | ropsten: { 8 | url: process.env.ROPSTEN_RPC, 9 | accounts: [process.env.PRIVATE_KEY] 10 | } 11 | }, 12 | paths: { 13 | artifacts: "./src/backend/artifacts", 14 | sources: "./src/backend/contracts", 15 | cache: "./src/backend/cache", 16 | tests: "./src/backend/test" 17 | }, 18 | }; 19 | -------------------------------------------------------------------------------- /src/frontend/components/Loading.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const Loading = ({val}) => { 4 | return ( 5 |
6 |

7 | 12 | {val} 13 |

14 |
15 | ) 16 | } 17 | 18 | export default Loading -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | 25 | node_modules 26 | .env 27 | coverage 28 | coverage.json 29 | typechain 30 | 31 | #Hardhat files 32 | cache 33 | artifacts 34 | -------------------------------------------------------------------------------- /src/frontend/components/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-link { 28 | color: #61dafb; 29 | } 30 | 31 | @keyframes App-logo-spin { 32 | from { 33 | transform: rotate(0deg); 34 | } 35 | to { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # ENS Domain marketplace 2 | List and sell your ens domains 3 | 4 | ## Technology Stack & Dependencies 5 | 6 | - Solidity (Writing Smart Contract) 7 | - Javascript (Game interaction) 8 | - [Alchemy](https://www.alchemy.com/) As a node provider 9 | - [NodeJS](https://nodejs.org/en/) To create hardhat project and install dependencis using npm 10 | - [Hardhat](https://hardhat.org/) Develop, test and deploy smart contract 11 | 12 | 13 | ### 1. Clone/Download the Repository 14 | 15 | ### 2. Install Dependencies: 16 | ``` 17 | $ npm install 18 | ``` 19 | 20 | ### 3. Deploy contracts to Ropsten and Run dapp 21 | - Input your private key and ropsten RPC in .env file 22 | ``` 23 | $ npx hardhat compile 24 | ``` 25 | ``` 26 | $ npm run deploy-ropsten 27 | ``` 28 | ``` 29 | $ npm start 30 | ``` 31 | 32 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import 'bootstrap'; 4 | import 'bootstrap/dist/css/bootstrap.min.css'; 5 | import App from './frontend/components/App'; 6 | import * as serviceWorker from './serviceWorker'; 7 | import { BrowserRouter } from 'react-router-dom'; 8 | 9 | const root = ReactDOM.createRoot(document.getElementById('root')); 10 | root.render( 11 | 12 | 13 | 14 | 15 | 16 | ); 17 | 18 | 19 | 20 | // If you want your app to work offline and load faster, you can change 21 | // unregister() to register() below. Note this comes with some pitfalls. 22 | // Learn more about service workers: https://bit.ly/CRA-PWA 23 | serviceWorker.unregister(); 24 | -------------------------------------------------------------------------------- /src/backend/scripts/deploy.js: -------------------------------------------------------------------------------- 1 | async function main() { 2 | 3 | const [deployer] = await ethers.getSigners(); 4 | 5 | console.log("Deploying contracts with the account:", deployer.address); 6 | console.log("Account balance:", (await deployer.getBalance()).toString()); 7 | 8 | 9 | // deploy contracts here: 10 | const Contract = await ethers.getContractFactory('EnsName'); 11 | const contract = await Contract.deploy(); 12 | 13 | console.log("Contract was deployed to Address: ", contract.address); 14 | // For each contract, pass the deployed contract and name to this function to save a copy of the contract ABI and address to the front end. 15 | saveFrontendFiles(contract, 'EnsName'); 16 | } 17 | 18 | function saveFrontendFiles(contract, name) { 19 | const fs = require("fs"); 20 | const contractsDir = __dirname + "/../../frontend/contractsData"; 21 | 22 | if (!fs.existsSync(contractsDir)) { 23 | fs.mkdirSync(contractsDir); 24 | } 25 | 26 | fs.writeFileSync( 27 | contractsDir + `/${name}-address.json`, 28 | JSON.stringify({ address: contract.address }, undefined, 2) 29 | ); 30 | 31 | const contractArtifact = artifacts.readArtifactSync(name); 32 | 33 | fs.writeFileSync( 34 | contractsDir + `/${name}.json`, 35 | JSON.stringify(contractArtifact, null, 2) 36 | ); 37 | } 38 | 39 | main() 40 | .then(() => process.exit(0)) 41 | .catch(error => { 42 | console.error(error); 43 | process.exit(1); 44 | }); 45 | -------------------------------------------------------------------------------- /src/backend/contracts/EnsName.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.7; 3 | 4 | import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; 5 | 6 | contract EnsName { 7 | uint256 public itemCount; 8 | 9 | struct Item{ 10 | uint256 itemId; 11 | string name; 12 | uint256 tokenId; 13 | uint256 price; 14 | bool listed; 15 | address payable seller; 16 | } 17 | 18 | mapping(uint256 => Item) public items; 19 | IERC721 public immutable ensContract; 20 | 21 | constructor (){ 22 | ensContract = IERC721(0x57f1887a8BF19b14fC0dF6Fd9B2acc9Af147eA85); 23 | } 24 | 25 | //Function to list the item for sale, approve this contract 26 | function listENS(string memory _name, uint256 _tokenId, uint256 _price) public{ 27 | require(_price > 0, "Price should be greater than 0"); 28 | itemCount++; 29 | items[itemCount] = Item( 30 | itemCount, 31 | _name, 32 | _tokenId, 33 | _price, 34 | true, 35 | payable(msg.sender) 36 | ); 37 | } 38 | 39 | //Function to buy the ENS - ie - transferFrom 40 | function buyENS(uint256 _itemId) public payable{ 41 | Item memory eachItem = items[_itemId]; 42 | require(msg.value >= eachItem.price, "Price sent is not correct"); 43 | require(_itemId > 0 && _itemId <= itemCount, "Wrong itemId"); 44 | require(eachItem.listed == true, "This item is has not been listed for sale"); 45 | ensContract.transferFrom(eachItem.seller, msg.sender, eachItem.tokenId); 46 | eachItem.listed = false; 47 | (bool sent, ) = eachItem.seller.call{value: msg.value}(""); 48 | require(sent, "Failed to send Ether"); 49 | } 50 | 51 | receive() external payable{} 52 | 53 | } -------------------------------------------------------------------------------- /src/frontend/components/Navbar.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Link } from 'react-router-dom'; 3 | 4 | const Navbar = ({logo, connectWallet, account, loading}) => { 5 | return ( 6 | 44 | ); 45 | }; 46 | 47 | export default Navbar; 48 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "make-web3-dapp", 3 | "keywords": [ 4 | "web3", 5 | "create-web3-dapp", 6 | "hardhat", 7 | "ethers", 8 | "solidity", 9 | "ethereum", 10 | "dapp" 11 | ], 12 | "dependencies": { 13 | "@babel/preset-react": "^7.18.6", 14 | "@nomicfoundation/hardhat-toolbox": "^1.0.2", 15 | "@openzeppelin/contracts": "^4.7.2", 16 | "@popperjs/core": "^2.11.5", 17 | "@testing-library/jest-dom": "^5.16.4", 18 | "@testing-library/react": "^13.3.0", 19 | "@testing-library/user-event": "^14.2.5", 20 | "alchemy-sdk": "^2.0.1", 21 | "bootstrap": "^5.1.3", 22 | "dotenv": "^16.0.1", 23 | "ethers": "^5.6.9", 24 | "hardhat": "^2.10.1", 25 | "jquery": "^3.6.0", 26 | "popper.js": "^1.16.1", 27 | "react": "^18.2.0", 28 | "react-dom": "^18.2.0", 29 | "react-router-dom": "^6.3.0", 30 | "react-scripts": "5.0.1", 31 | "web-vitals": "^2.1.4" 32 | }, 33 | "scripts": { 34 | "deploy": "npx hardhat run src/backend/scripts/deploy.js", 35 | "deploy-ropsten": "npx hardhat run src/backend/scripts/deploy.js --network ropsten", 36 | "start": "react-scripts start", 37 | "build": "react-scripts build", 38 | "test": "react-scripts test", 39 | "eject": "react-scripts eject" 40 | }, 41 | "eslintConfig": { 42 | "extends": [ 43 | "react-app", 44 | "react-app/jest" 45 | ] 46 | }, 47 | "browserslist": { 48 | "production": [ 49 | ">0.2%", 50 | "not dead", 51 | "not op_mini all" 52 | ], 53 | "development": [ 54 | "last 1 chrome version", 55 | "last 1 firefox version", 56 | "last 1 safari version" 57 | ] 58 | }, 59 | "devDependencies": { 60 | "@babel/preset-env": "^7.18.9", 61 | "@nomicfoundation/hardhat-chai-matchers": "^1.0.2", 62 | "@nomicfoundation/hardhat-network-helpers": "^1.0.3", 63 | "@nomiclabs/hardhat-ethers": "^2.1.0", 64 | "@nomiclabs/hardhat-etherscan": "^3.1.0", 65 | "@typechain/ethers-v5": "^10.1.0", 66 | "@typechain/hardhat": "^6.1.2", 67 | "@types/chai": "^4.3.3", 68 | "@types/mocha": "^9.1.1", 69 | "chai": "^4.3.6", 70 | "hardhat-gas-reporter": "^1.0.8", 71 | "solidity-coverage": "^0.7.21", 72 | "ts-node": "^10.9.1", 73 | "typechain": "^8.1.0", 74 | "typescript": "^4.7.4" 75 | }, 76 | "bin": { 77 | "make-web3-dapp": "./bin/generate-app.js" 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/frontend/components/BuyEns.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react'; 2 | import Loading from './Loading'; 3 | 4 | const BuyEns = ({ marketplace, ENSContract }) => { 5 | const [allListings, setAllListings] = useState([]); 6 | const [loading, setLoading] = useState(false); 7 | const [buyLoading, setBuyLoading] = useState(false); 8 | 9 | useEffect(() => { 10 | if (marketplace !== '') { 11 | allListing(); 12 | } 13 | }, [marketplace]); 14 | 15 | const allListing = async () => { 16 | setLoading(true); 17 | try { 18 | const itemCount = await marketplace.itemCount(); 19 | let items = []; 20 | for (let i = 1; i <= itemCount; i++) { 21 | const item = await marketplace.items(i); 22 | 23 | if (item.listed) { 24 | const itemId = item.itemId.toString(); 25 | const price = item.price.toString(); 26 | //add all these to an array and save in state 27 | items.push({ 28 | price: price, 29 | name: item.name, 30 | itemId: itemId, 31 | seller: item.seller, 32 | }); 33 | } 34 | } 35 | setLoading(false); 36 | // console.log(items); 37 | setAllListings(items); 38 | } catch (error) { 39 | setLoading(false); 40 | console.log(error); 41 | } 42 | }; 43 | 44 | const buyListing = async (item) => { 45 | setBuyLoading(true) 46 | try { 47 | const tx = await marketplace.buyENS(item.itemId, { 48 | value: item.price, 49 | }); 50 | await tx.wait(); 51 | alert('Congrats! You have bought the ENS', item.name); 52 | setBuyLoading(false); 53 | allListing(); 54 | } catch (error) { 55 | setBuyLoading(false); 56 | console.log(error); 57 | } 58 | }; 59 | 60 | return ( 61 |
62 |

Explore and Buy ENS

63 | {loading ? ( 64 | 65 | ) : allListings.length === 0 ? ( 66 |
There are currently no ENS for Sale
67 | ) : ( 68 |
69 | {allListings.map((item, i) => ( 70 |
71 |
72 |
73 |
{item.name}
74 |
75 | Price: {item.price / 10 ** 18} ETH 76 |
77 | 94 |
95 |
96 |
97 | ) 98 | )} 99 |
100 | )} 101 |
102 | ); 103 | }; 104 | 105 | export default BuyEns; 106 | -------------------------------------------------------------------------------- /src/frontend/components/ListItem.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react'; 2 | import { Alchemy, Network } from 'alchemy-sdk'; 3 | import { ethers } from 'ethers'; 4 | import Loading from './Loading'; 5 | 6 | const ListItem = ({ EnsNameAddress, marketplace, ENSContract, account }) => { 7 | const [ensNames, setEnsNames] = useState([]); 8 | const [price, setPrice] = useState(null); 9 | const [loading, setLoading] = useState(false); 10 | const [loadPage, setLoadPage] = useState(false); 11 | 12 | useEffect(() => { 13 | if (account != null) { 14 | getAllENS(); 15 | } 16 | }, [account]); 17 | 18 | const getAllENS = async () => { 19 | setLoadPage(true); 20 | const config = { 21 | apiKey: process.env.ALCHEMY_API, 22 | network: Network.ETH_ROPSTEN, 23 | }; 24 | 25 | const alchemy = new Alchemy(config); 26 | 27 | const ensContractAddress = '0x57f1887a8BF19b14fC0dF6Fd9B2acc9Af147eA85'; 28 | const ens = await alchemy.nft.getNftsForOwner(account, { 29 | contractAddresses: [ensContractAddress], 30 | }); 31 | 32 | setEnsNames(ens.ownedNfts); 33 | console.log(ens.ownedNfts); 34 | setLoadPage(false); 35 | }; 36 | 37 | const listForSale = async (tokId, ensName) => { 38 | setLoading(true); 39 | try { 40 | const tx = await ENSContract.setApprovalForAll( 41 | EnsNameAddress.address, 42 | true 43 | ); 44 | await tx.wait(); 45 | let priceInEth = ethers.utils.parseEther(price.toString()); 46 | const tx2 = await marketplace.listENS(ensName, tokId, priceInEth); 47 | await tx2.wait(); 48 | alert('Awesome! You have now Listed your Item for Sale!'); 49 | setLoading(false); 50 | } catch (err) { 51 | setLoading(false); 52 | console.log(err); 53 | } 54 | }; 55 | 56 | return ( 57 |
58 | {loadPage ? ( 59 | 60 | ) : ( 61 |
62 |

You Own the Following ENS Domains:

63 | 64 | {ensNames.length === 0 ? ( 65 |
66 |

Sorry You do Not Own any ENS Domains!

67 |
68 | ) : loading ? ( 69 | 70 | ) : ( 71 | ensNames.map((na, i) => ( 72 |
73 | 79 | setPrice(e.target.value)} 83 | placeholder='Enter the Price in ETH at which you want to List' 84 | required 85 | /> 86 | 94 |
95 | )) 96 | )} 97 |
98 | )} 99 |
100 | ); 101 | }; 102 | 103 | export default ListItem; 104 | 105 | { 106 | /* 107 | */ 108 | } 109 | -------------------------------------------------------------------------------- /src/frontend/components/App.js: -------------------------------------------------------------------------------- 1 | import './App.css'; 2 | import logo from './logo.png'; 3 | import EnsNameAbi from '../contractsData/EnsName.json' 4 | import EnsNameAddress from '../contractsData/EnsName-address.json' 5 | import ensAbi from './ENSContract.json' 6 | import React, { useEffect, useState } from 'react'; 7 | import Navbar from './Navbar'; 8 | import { ethers } from 'ethers'; 9 | import ListItem from './ListItem'; 10 | import { Route, Routes } from 'react-router-dom'; 11 | import BuyEns from './BuyEns'; 12 | 13 | const App = () => { 14 | 15 | 16 | 17 | 18 | const [account, setAccount] = useState(null); 19 | const [loading, setLoading] = useState(false); 20 | const [marketplace, setMarketplace] = useState(''); 21 | const [ENSContract, setENSContract] = useState(''); 22 | 23 | 24 | const ENSContractAddress = "0x57f1887a8BF19b14fC0dF6Fd9B2acc9Af147eA85"; 25 | 26 | useEffect(() => { 27 | checkIfWalletIsConnected(); 28 | 29 | window.ethereum.on('chainChanged', (chainId) => { 30 | window.location.reload(); 31 | }) 32 | 33 | window.ethereum.on('accountsChanged', async function (accounts) { 34 | setAccount(accounts[0]) 35 | await checkIfWalletIsConnected(); 36 | window.location.reload(); 37 | }) 38 | }, []); 39 | 40 | 41 | 42 | 43 | const checkIfWalletIsConnected = async () => { 44 | try { 45 | setLoading(true) 46 | if (!window.ethereum) { 47 | alert('No Web3 Provider Detected. Kindly Install Metamask'); 48 | } else { 49 | const accounts = await window.ethereum.request({ 50 | method: 'eth_accounts', 51 | }); 52 | if (accounts.length !== 0) { 53 | setAccount(accounts[0]); 54 | loadContracts(); 55 | } else { 56 | console.log('Please Connect Your Wallet'); 57 | } 58 | } 59 | } catch (err) { 60 | setLoading(false); 61 | console.log(err); 62 | } 63 | }; 64 | 65 | const connectWallet = async () => { 66 | try { 67 | if (!window.ethereum) { 68 | alert('No Web3 Provider Detected. Kindly Install Metamask'); 69 | } else { 70 | setLoading(true); 71 | const accounts = await window.ethereum.request({ 72 | method: 'eth_requestAccounts', 73 | }); 74 | setAccount(accounts[0]); 75 | loadContracts(); 76 | } 77 | setLoading(false); 78 | } catch (err) { 79 | setLoading(false); 80 | console.log(err); 81 | } 82 | }; 83 | 84 | //loading contracts 85 | const loadContracts = async () => { 86 | try { 87 | const provider = new ethers.providers.Web3Provider(window.ethereum); 88 | const signer = provider.getSigner(); 89 | const mp = new ethers.Contract( 90 | EnsNameAddress.address, 91 | EnsNameAbi.abi, 92 | signer 93 | ); 94 | setMarketplace(mp); 95 | const ensCont = new ethers.Contract(ENSContractAddress, ensAbi.abi, signer); 96 | setENSContract(ensCont); 97 | 98 | // console.log(await signer.provider.getCode(marketplace)) 99 | 100 | console.log('Contracts Loaded!'); 101 | setLoading(false); 102 | } catch (err) { 103 | setLoading(false); 104 | console.log(err); 105 | } 106 | }; 107 | 108 | 109 | return ( 110 |
111 | 112 |
113 | 114 | }> 115 | }> 116 | 117 | 118 |
119 |
120 | ); 121 | }; 122 | 123 | export default App; 124 | -------------------------------------------------------------------------------- /src/backend/test/test.js: -------------------------------------------------------------------------------- 1 | const { 2 | time, 3 | loadFixture, 4 | } = require("@nomicfoundation/hardhat-network-helpers"); 5 | const { anyValue } = require("@nomicfoundation/hardhat-chai-matchers/withArgs"); 6 | const { expect } = require("chai"); 7 | 8 | describe("Lock", function () { 9 | // We define a fixture to reuse the same setup in every test. 10 | // We use loadFixture to run this setup once, snapshot that state, 11 | // and reset Hardhat Network to that snapshopt in every test. 12 | async function deployOneYearLockFixture() { 13 | const ONE_YEAR_IN_SECS = 365 * 24 * 60 * 60; 14 | const ONE_GWEI = 1_000_000_000; 15 | 16 | const lockedAmount = ONE_GWEI; 17 | const unlockTime = (await time.latest()) + ONE_YEAR_IN_SECS; 18 | 19 | // Contracts are deployed using the first signer/account by default 20 | const [owner, otherAccount] = await ethers.getSigners(); 21 | 22 | const Lock = await ethers.getContractFactory("Lock"); 23 | const lock = await Lock.deploy(unlockTime, { value: lockedAmount }); 24 | 25 | return { lock, unlockTime, lockedAmount, owner, otherAccount }; 26 | } 27 | 28 | describe("Deployment", function () { 29 | it("Should set the right unlockTime", async function () { 30 | const { lock, unlockTime } = await loadFixture(deployOneYearLockFixture); 31 | 32 | expect(await lock.unlockTime()).to.equal(unlockTime); 33 | }); 34 | 35 | it("Should set the right owner", async function () { 36 | const { lock, owner } = await loadFixture(deployOneYearLockFixture); 37 | 38 | expect(await lock.owner()).to.equal(owner.address); 39 | }); 40 | 41 | it("Should receive and store the funds to lock", async function () { 42 | const { lock, lockedAmount } = await loadFixture( 43 | deployOneYearLockFixture 44 | ); 45 | 46 | expect(await ethers.provider.getBalance(lock.address)).to.equal( 47 | lockedAmount 48 | ); 49 | }); 50 | 51 | it("Should fail if the unlockTime is not in the future", async function () { 52 | // We don't use the fixture here because we want a different deployment 53 | const latestTime = await time.latest(); 54 | const Lock = await ethers.getContractFactory("Lock"); 55 | await expect(Lock.deploy(latestTime, { value: 1 })).to.be.revertedWith( 56 | "Unlock time should be in the future" 57 | ); 58 | }); 59 | }); 60 | 61 | describe("Withdrawals", function () { 62 | describe("Validations", function () { 63 | it("Should revert with the right error if called too soon", async function () { 64 | const { lock } = await loadFixture(deployOneYearLockFixture); 65 | 66 | await expect(lock.withdraw()).to.be.revertedWith( 67 | "You can't withdraw yet" 68 | ); 69 | }); 70 | 71 | it("Should revert with the right error if called from another account", async function () { 72 | const { lock, unlockTime, otherAccount } = await loadFixture( 73 | deployOneYearLockFixture 74 | ); 75 | 76 | // We can increase the time in Hardhat Network 77 | await time.increaseTo(unlockTime); 78 | 79 | // We use lock.connect() to send a transaction from another account 80 | await expect(lock.connect(otherAccount).withdraw()).to.be.revertedWith( 81 | "You aren't the owner" 82 | ); 83 | }); 84 | 85 | it("Shouldn't fail if the unlockTime has arrived and the owner calls it", async function () { 86 | const { lock, unlockTime } = await loadFixture( 87 | deployOneYearLockFixture 88 | ); 89 | 90 | // Transactions are sent using the first signer by default 91 | await time.increaseTo(unlockTime); 92 | 93 | await expect(lock.withdraw()).not.to.be.reverted; 94 | }); 95 | }); 96 | 97 | describe("Events", function () { 98 | it("Should emit an event on withdrawals", async function () { 99 | const { lock, unlockTime, lockedAmount } = await loadFixture( 100 | deployOneYearLockFixture 101 | ); 102 | 103 | await time.increaseTo(unlockTime); 104 | 105 | await expect(lock.withdraw()) 106 | .to.emit(lock, "Withdrawal") 107 | .withArgs(lockedAmount, anyValue); // We accept any value as `when` arg 108 | }); 109 | }); 110 | 111 | describe("Transfers", function () { 112 | it("Should transfer the funds to the owner", async function () { 113 | const { lock, unlockTime, lockedAmount, owner } = await loadFixture( 114 | deployOneYearLockFixture 115 | ); 116 | 117 | await time.increaseTo(unlockTime); 118 | 119 | await expect(lock.withdraw()).to.changeEtherBalances( 120 | [owner, lock], 121 | [lockedAmount, -lockedAmount] 122 | ); 123 | }); 124 | }); 125 | }); 126 | }); 127 | -------------------------------------------------------------------------------- /src/serviceWorker.js: -------------------------------------------------------------------------------- 1 | // This optional code is used to register a service worker. 2 | // register() is not called by default. 3 | 4 | // This lets the app load faster on subsequent visits in production, and gives 5 | // it offline capabilities. However, it also means that developers (and users) 6 | // will only see deployed updates on subsequent visits to a page, after all the 7 | // existing tabs open on the page have been closed, since previously cached 8 | // resources are updated in the background. 9 | 10 | // To learn more about the benefits of this model and instructions on how to 11 | // opt-in, read https://bit.ly/CRA-PWA 12 | 13 | const isLocalhost = Boolean( 14 | window.location.hostname === 'localhost' || 15 | // [::1] is the IPv6 localhost address. 16 | window.location.hostname === '[::1]' || 17 | // 127.0.0.1/8 is considered localhost for IPv4. 18 | window.location.hostname.match( 19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 20 | ) 21 | ); 22 | 23 | export function register(config) { 24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 25 | // The URL constructor is available in all browsers that support SW. 26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); 27 | if (publicUrl.origin !== window.location.origin) { 28 | // Our service worker won't work if PUBLIC_URL is on a different origin 29 | // from what our page is served on. This might happen if a CDN is used to 30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374 31 | return; 32 | } 33 | 34 | window.addEventListener('load', () => { 35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 36 | 37 | if (isLocalhost) { 38 | // This is running on localhost. Let's check if a service worker still exists or not. 39 | checkValidServiceWorker(swUrl, config); 40 | 41 | // Add some additional logging to localhost, pointing developers to the 42 | // service worker/PWA documentation. 43 | navigator.serviceWorker.ready.then(() => { 44 | console.log( 45 | 'This web app is being served cache-first by a service ' + 46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA' 47 | ); 48 | }); 49 | } else { 50 | // Is not localhost. Just register service worker 51 | registerValidSW(swUrl, config); 52 | } 53 | }); 54 | } 55 | } 56 | 57 | function registerValidSW(swUrl, config) { 58 | navigator.serviceWorker 59 | .register(swUrl) 60 | .then(registration => { 61 | registration.onupdatefound = () => { 62 | const installingWorker = registration.installing; 63 | if (installingWorker == null) { 64 | return; 65 | } 66 | installingWorker.onstatechange = () => { 67 | if (installingWorker.state === 'installed') { 68 | if (navigator.serviceWorker.controller) { 69 | // At this point, the updated precached content has been fetched, 70 | // but the previous service worker will still serve the older 71 | // content until all client tabs are closed. 72 | console.log( 73 | 'New content is available and will be used when all ' + 74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.' 75 | ); 76 | 77 | // Execute callback 78 | if (config && config.onUpdate) { 79 | config.onUpdate(registration); 80 | } 81 | } else { 82 | // At this point, everything has been precached. 83 | // It's the perfect time to display a 84 | // "Content is cached for offline use." message. 85 | console.log('Content is cached for offline use.'); 86 | 87 | // Execute callback 88 | if (config && config.onSuccess) { 89 | config.onSuccess(registration); 90 | } 91 | } 92 | } 93 | }; 94 | }; 95 | }) 96 | .catch(error => { 97 | console.error('Error during service worker registration:', error); 98 | }); 99 | } 100 | 101 | function checkValidServiceWorker(swUrl, config) { 102 | // Check if the service worker can be found. If it can't reload the page. 103 | fetch(swUrl) 104 | .then(response => { 105 | // Ensure service worker exists, and that we really are getting a JS file. 106 | const contentType = response.headers.get('content-type'); 107 | if ( 108 | response.status === 404 || 109 | (contentType != null && contentType.indexOf('javascript') === -1) 110 | ) { 111 | // No service worker found. Probably a different app. Reload the page. 112 | navigator.serviceWorker.ready.then(registration => { 113 | registration.unregister().then(() => { 114 | window.location.reload(); 115 | }); 116 | }); 117 | } else { 118 | // Service worker found. Proceed as normal. 119 | registerValidSW(swUrl, config); 120 | } 121 | }) 122 | .catch(() => { 123 | console.log( 124 | 'No internet connection found. App is running in offline mode.' 125 | ); 126 | }); 127 | } 128 | 129 | export function unregister() { 130 | if ('serviceWorker' in navigator) { 131 | navigator.serviceWorker.ready.then(registration => { 132 | registration.unregister(); 133 | }); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/frontend/components/ENSContract.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "hh-sol-artifact-1", 3 | "contractName": "EnsName", 4 | "abi": [ 5 | { 6 | "inputs": [ 7 | { "internalType": "contract ENS", "name": "_ens", "type": "address" }, 8 | { "internalType": "bytes32", "name": "_baseNode", "type": "bytes32" } 9 | ], 10 | "payable": false, 11 | "stateMutability": "nonpayable", 12 | "type": "constructor" 13 | }, 14 | { 15 | "anonymous": false, 16 | "inputs": [ 17 | { 18 | "indexed": true, 19 | "internalType": "address", 20 | "name": "owner", 21 | "type": "address" 22 | }, 23 | { 24 | "indexed": true, 25 | "internalType": "address", 26 | "name": "approved", 27 | "type": "address" 28 | }, 29 | { 30 | "indexed": true, 31 | "internalType": "uint256", 32 | "name": "tokenId", 33 | "type": "uint256" 34 | } 35 | ], 36 | "name": "Approval", 37 | "type": "event" 38 | }, 39 | { 40 | "anonymous": false, 41 | "inputs": [ 42 | { 43 | "indexed": true, 44 | "internalType": "address", 45 | "name": "owner", 46 | "type": "address" 47 | }, 48 | { 49 | "indexed": true, 50 | "internalType": "address", 51 | "name": "operator", 52 | "type": "address" 53 | }, 54 | { 55 | "indexed": false, 56 | "internalType": "bool", 57 | "name": "approved", 58 | "type": "bool" 59 | } 60 | ], 61 | "name": "ApprovalForAll", 62 | "type": "event" 63 | }, 64 | { 65 | "anonymous": false, 66 | "inputs": [ 67 | { 68 | "indexed": true, 69 | "internalType": "address", 70 | "name": "controller", 71 | "type": "address" 72 | } 73 | ], 74 | "name": "ControllerAdded", 75 | "type": "event" 76 | }, 77 | { 78 | "anonymous": false, 79 | "inputs": [ 80 | { 81 | "indexed": true, 82 | "internalType": "address", 83 | "name": "controller", 84 | "type": "address" 85 | } 86 | ], 87 | "name": "ControllerRemoved", 88 | "type": "event" 89 | }, 90 | { 91 | "anonymous": false, 92 | "inputs": [ 93 | { 94 | "indexed": true, 95 | "internalType": "uint256", 96 | "name": "id", 97 | "type": "uint256" 98 | }, 99 | { 100 | "indexed": true, 101 | "internalType": "address", 102 | "name": "owner", 103 | "type": "address" 104 | }, 105 | { 106 | "indexed": false, 107 | "internalType": "uint256", 108 | "name": "expires", 109 | "type": "uint256" 110 | } 111 | ], 112 | "name": "NameMigrated", 113 | "type": "event" 114 | }, 115 | { 116 | "anonymous": false, 117 | "inputs": [ 118 | { 119 | "indexed": true, 120 | "internalType": "uint256", 121 | "name": "id", 122 | "type": "uint256" 123 | }, 124 | { 125 | "indexed": true, 126 | "internalType": "address", 127 | "name": "owner", 128 | "type": "address" 129 | }, 130 | { 131 | "indexed": false, 132 | "internalType": "uint256", 133 | "name": "expires", 134 | "type": "uint256" 135 | } 136 | ], 137 | "name": "NameRegistered", 138 | "type": "event" 139 | }, 140 | { 141 | "anonymous": false, 142 | "inputs": [ 143 | { 144 | "indexed": true, 145 | "internalType": "uint256", 146 | "name": "id", 147 | "type": "uint256" 148 | }, 149 | { 150 | "indexed": false, 151 | "internalType": "uint256", 152 | "name": "expires", 153 | "type": "uint256" 154 | } 155 | ], 156 | "name": "NameRenewed", 157 | "type": "event" 158 | }, 159 | { 160 | "anonymous": false, 161 | "inputs": [ 162 | { 163 | "indexed": true, 164 | "internalType": "address", 165 | "name": "previousOwner", 166 | "type": "address" 167 | }, 168 | { 169 | "indexed": true, 170 | "internalType": "address", 171 | "name": "newOwner", 172 | "type": "address" 173 | } 174 | ], 175 | "name": "OwnershipTransferred", 176 | "type": "event" 177 | }, 178 | { 179 | "anonymous": false, 180 | "inputs": [ 181 | { 182 | "indexed": true, 183 | "internalType": "address", 184 | "name": "from", 185 | "type": "address" 186 | }, 187 | { 188 | "indexed": true, 189 | "internalType": "address", 190 | "name": "to", 191 | "type": "address" 192 | }, 193 | { 194 | "indexed": true, 195 | "internalType": "uint256", 196 | "name": "tokenId", 197 | "type": "uint256" 198 | } 199 | ], 200 | "name": "Transfer", 201 | "type": "event" 202 | }, 203 | { 204 | "constant": true, 205 | "inputs": [], 206 | "name": "GRACE_PERIOD", 207 | "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], 208 | "payable": false, 209 | "stateMutability": "view", 210 | "type": "function" 211 | }, 212 | { 213 | "constant": false, 214 | "inputs": [ 215 | { "internalType": "address", "name": "controller", "type": "address" } 216 | ], 217 | "name": "addController", 218 | "outputs": [], 219 | "payable": false, 220 | "stateMutability": "nonpayable", 221 | "type": "function" 222 | }, 223 | { 224 | "constant": false, 225 | "inputs": [ 226 | { "internalType": "address", "name": "to", "type": "address" }, 227 | { "internalType": "uint256", "name": "tokenId", "type": "uint256" } 228 | ], 229 | "name": "approve", 230 | "outputs": [], 231 | "payable": false, 232 | "stateMutability": "nonpayable", 233 | "type": "function" 234 | }, 235 | { 236 | "constant": true, 237 | "inputs": [ 238 | { "internalType": "uint256", "name": "id", "type": "uint256" } 239 | ], 240 | "name": "available", 241 | "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], 242 | "payable": false, 243 | "stateMutability": "view", 244 | "type": "function" 245 | }, 246 | { 247 | "constant": true, 248 | "inputs": [ 249 | { "internalType": "address", "name": "owner", "type": "address" } 250 | ], 251 | "name": "balanceOf", 252 | "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], 253 | "payable": false, 254 | "stateMutability": "view", 255 | "type": "function" 256 | }, 257 | { 258 | "constant": true, 259 | "inputs": [], 260 | "name": "baseNode", 261 | "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], 262 | "payable": false, 263 | "stateMutability": "view", 264 | "type": "function" 265 | }, 266 | { 267 | "constant": true, 268 | "inputs": [{ "internalType": "address", "name": "", "type": "address" }], 269 | "name": "controllers", 270 | "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], 271 | "payable": false, 272 | "stateMutability": "view", 273 | "type": "function" 274 | }, 275 | { 276 | "constant": true, 277 | "inputs": [], 278 | "name": "ens", 279 | "outputs": [ 280 | { "internalType": "contract ENS", "name": "", "type": "address" } 281 | ], 282 | "payable": false, 283 | "stateMutability": "view", 284 | "type": "function" 285 | }, 286 | { 287 | "constant": true, 288 | "inputs": [ 289 | { "internalType": "uint256", "name": "tokenId", "type": "uint256" } 290 | ], 291 | "name": "getApproved", 292 | "outputs": [{ "internalType": "address", "name": "", "type": "address" }], 293 | "payable": false, 294 | "stateMutability": "view", 295 | "type": "function" 296 | }, 297 | { 298 | "constant": true, 299 | "inputs": [ 300 | { "internalType": "address", "name": "owner", "type": "address" }, 301 | { "internalType": "address", "name": "operator", "type": "address" } 302 | ], 303 | "name": "isApprovedForAll", 304 | "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], 305 | "payable": false, 306 | "stateMutability": "view", 307 | "type": "function" 308 | }, 309 | { 310 | "constant": true, 311 | "inputs": [], 312 | "name": "isOwner", 313 | "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], 314 | "payable": false, 315 | "stateMutability": "view", 316 | "type": "function" 317 | }, 318 | { 319 | "constant": true, 320 | "inputs": [ 321 | { "internalType": "uint256", "name": "id", "type": "uint256" } 322 | ], 323 | "name": "nameExpires", 324 | "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], 325 | "payable": false, 326 | "stateMutability": "view", 327 | "type": "function" 328 | }, 329 | { 330 | "constant": true, 331 | "inputs": [], 332 | "name": "owner", 333 | "outputs": [{ "internalType": "address", "name": "", "type": "address" }], 334 | "payable": false, 335 | "stateMutability": "view", 336 | "type": "function" 337 | }, 338 | { 339 | "constant": true, 340 | "inputs": [ 341 | { "internalType": "uint256", "name": "tokenId", "type": "uint256" } 342 | ], 343 | "name": "ownerOf", 344 | "outputs": [{ "internalType": "address", "name": "", "type": "address" }], 345 | "payable": false, 346 | "stateMutability": "view", 347 | "type": "function" 348 | }, 349 | { 350 | "constant": false, 351 | "inputs": [ 352 | { "internalType": "uint256", "name": "id", "type": "uint256" }, 353 | { "internalType": "address", "name": "owner", "type": "address" } 354 | ], 355 | "name": "reclaim", 356 | "outputs": [], 357 | "payable": false, 358 | "stateMutability": "nonpayable", 359 | "type": "function" 360 | }, 361 | { 362 | "constant": false, 363 | "inputs": [ 364 | { "internalType": "uint256", "name": "id", "type": "uint256" }, 365 | { "internalType": "address", "name": "owner", "type": "address" }, 366 | { "internalType": "uint256", "name": "duration", "type": "uint256" } 367 | ], 368 | "name": "register", 369 | "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], 370 | "payable": false, 371 | "stateMutability": "nonpayable", 372 | "type": "function" 373 | }, 374 | { 375 | "constant": false, 376 | "inputs": [ 377 | { "internalType": "uint256", "name": "id", "type": "uint256" }, 378 | { "internalType": "address", "name": "owner", "type": "address" }, 379 | { "internalType": "uint256", "name": "duration", "type": "uint256" } 380 | ], 381 | "name": "registerOnly", 382 | "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], 383 | "payable": false, 384 | "stateMutability": "nonpayable", 385 | "type": "function" 386 | }, 387 | { 388 | "constant": false, 389 | "inputs": [ 390 | { "internalType": "address", "name": "controller", "type": "address" } 391 | ], 392 | "name": "removeController", 393 | "outputs": [], 394 | "payable": false, 395 | "stateMutability": "nonpayable", 396 | "type": "function" 397 | }, 398 | { 399 | "constant": false, 400 | "inputs": [ 401 | { "internalType": "uint256", "name": "id", "type": "uint256" }, 402 | { "internalType": "uint256", "name": "duration", "type": "uint256" } 403 | ], 404 | "name": "renew", 405 | "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], 406 | "payable": false, 407 | "stateMutability": "nonpayable", 408 | "type": "function" 409 | }, 410 | { 411 | "constant": false, 412 | "inputs": [], 413 | "name": "renounceOwnership", 414 | "outputs": [], 415 | "payable": false, 416 | "stateMutability": "nonpayable", 417 | "type": "function" 418 | }, 419 | { 420 | "constant": false, 421 | "inputs": [ 422 | { "internalType": "address", "name": "from", "type": "address" }, 423 | { "internalType": "address", "name": "to", "type": "address" }, 424 | { "internalType": "uint256", "name": "tokenId", "type": "uint256" } 425 | ], 426 | "name": "safeTransferFrom", 427 | "outputs": [], 428 | "payable": false, 429 | "stateMutability": "nonpayable", 430 | "type": "function" 431 | }, 432 | { 433 | "constant": false, 434 | "inputs": [ 435 | { "internalType": "address", "name": "from", "type": "address" }, 436 | { "internalType": "address", "name": "to", "type": "address" }, 437 | { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, 438 | { "internalType": "bytes", "name": "_data", "type": "bytes" } 439 | ], 440 | "name": "safeTransferFrom", 441 | "outputs": [], 442 | "payable": false, 443 | "stateMutability": "nonpayable", 444 | "type": "function" 445 | }, 446 | { 447 | "constant": false, 448 | "inputs": [ 449 | { "internalType": "address", "name": "to", "type": "address" }, 450 | { "internalType": "bool", "name": "approved", "type": "bool" } 451 | ], 452 | "name": "setApprovalForAll", 453 | "outputs": [], 454 | "payable": false, 455 | "stateMutability": "nonpayable", 456 | "type": "function" 457 | }, 458 | { 459 | "constant": false, 460 | "inputs": [ 461 | { "internalType": "address", "name": "resolver", "type": "address" } 462 | ], 463 | "name": "setResolver", 464 | "outputs": [], 465 | "payable": false, 466 | "stateMutability": "nonpayable", 467 | "type": "function" 468 | }, 469 | { 470 | "constant": true, 471 | "inputs": [ 472 | { "internalType": "bytes4", "name": "interfaceID", "type": "bytes4" } 473 | ], 474 | "name": "supportsInterface", 475 | "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], 476 | "payable": false, 477 | "stateMutability": "view", 478 | "type": "function" 479 | }, 480 | { 481 | "constant": false, 482 | "inputs": [ 483 | { "internalType": "address", "name": "from", "type": "address" }, 484 | { "internalType": "address", "name": "to", "type": "address" }, 485 | { "internalType": "uint256", "name": "tokenId", "type": "uint256" } 486 | ], 487 | "name": "transferFrom", 488 | "outputs": [], 489 | "payable": false, 490 | "stateMutability": "nonpayable", 491 | "type": "function" 492 | }, 493 | { 494 | "constant": false, 495 | "inputs": [ 496 | { "internalType": "address", "name": "newOwner", "type": "address" } 497 | ], 498 | "name": "transferOwnership", 499 | "outputs": [], 500 | "payable": false, 501 | "stateMutability": "nonpayable", 502 | "type": "function" 503 | } 504 | ] 505 | } 506 | -------------------------------------------------------------------------------- /src/frontend/contractsData/EnsName.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "hh-sol-artifact-1", 3 | "contractName": "EnsName", 4 | "sourceName": "src/backend/contracts/EnsName.sol", 5 | "abi": [ 6 | { 7 | "inputs": [], 8 | "stateMutability": "nonpayable", 9 | "type": "constructor" 10 | }, 11 | { 12 | "inputs": [ 13 | { 14 | "internalType": "uint256", 15 | "name": "_itemId", 16 | "type": "uint256" 17 | } 18 | ], 19 | "name": "buyENS", 20 | "outputs": [], 21 | "stateMutability": "payable", 22 | "type": "function" 23 | }, 24 | { 25 | "inputs": [], 26 | "name": "ensContract", 27 | "outputs": [ 28 | { 29 | "internalType": "contract IERC721", 30 | "name": "", 31 | "type": "address" 32 | } 33 | ], 34 | "stateMutability": "view", 35 | "type": "function" 36 | }, 37 | { 38 | "inputs": [], 39 | "name": "itemCount", 40 | "outputs": [ 41 | { 42 | "internalType": "uint256", 43 | "name": "", 44 | "type": "uint256" 45 | } 46 | ], 47 | "stateMutability": "view", 48 | "type": "function" 49 | }, 50 | { 51 | "inputs": [ 52 | { 53 | "internalType": "uint256", 54 | "name": "", 55 | "type": "uint256" 56 | } 57 | ], 58 | "name": "items", 59 | "outputs": [ 60 | { 61 | "internalType": "uint256", 62 | "name": "itemId", 63 | "type": "uint256" 64 | }, 65 | { 66 | "internalType": "string", 67 | "name": "name", 68 | "type": "string" 69 | }, 70 | { 71 | "internalType": "uint256", 72 | "name": "tokenId", 73 | "type": "uint256" 74 | }, 75 | { 76 | "internalType": "uint256", 77 | "name": "price", 78 | "type": "uint256" 79 | }, 80 | { 81 | "internalType": "bool", 82 | "name": "listed", 83 | "type": "bool" 84 | }, 85 | { 86 | "internalType": "address payable", 87 | "name": "seller", 88 | "type": "address" 89 | } 90 | ], 91 | "stateMutability": "view", 92 | "type": "function" 93 | }, 94 | { 95 | "inputs": [ 96 | { 97 | "internalType": "string", 98 | "name": "_name", 99 | "type": "string" 100 | }, 101 | { 102 | "internalType": "uint256", 103 | "name": "_tokenId", 104 | "type": "uint256" 105 | }, 106 | { 107 | "internalType": "uint256", 108 | "name": "_price", 109 | "type": "uint256" 110 | } 111 | ], 112 | "name": "listENS", 113 | "outputs": [], 114 | "stateMutability": "nonpayable", 115 | "type": "function" 116 | }, 117 | { 118 | "stateMutability": "payable", 119 | "type": "receive" 120 | } 121 | ], 122 | "bytecode": "0x60a060405234801561001057600080fd5b507357f1887a8bf19b14fc0df6fd9b2acc9af147ea8573ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff168152505060805161100461007b6000396000818161029901526105da01526110046000f3fe60806040526004361061004e5760003560e01c80634783de501461005a5780636881e763146100835780636bfb0d01146100ae578063bfb231d2146100d9578063f3eee3851461011b57610055565b3661005557005b600080fd5b34801561006657600080fd5b50610081600480360381019061007c9190610968565b610137565b005b34801561008f57600080fd5b50610098610297565b6040516100a59190610a56565b60405180910390f35b3480156100ba57600080fd5b506100c36102bb565b6040516100d09190610a80565b60405180910390f35b3480156100e557600080fd5b5061010060048036038101906100fb9190610a9b565b6102c1565b60405161011296959493929190610b8c565b60405180910390f35b61013560048036038101906101309190610a9b565b6103b2565b005b6000811161017a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017190610c40565b60405180910390fd5b60008081548092919061018c90610c8f565b91905055506040518060c0016040528060005481526020018481526020018381526020018281526020016001151581526020013373ffffffffffffffffffffffffffffffffffffffff168152506001600080548152602001908152602001600020600082015181600001556020820151816001019080519060200190610213929190610735565b50604082015181600201556060820151816003015560808201518160040160006101000a81548160ff02191690831515021790555060a08201518160040160016101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60005481565b60016020528060005260406000206000915090508060000154908060010180546102ea90610d07565b80601f016020809104026020016040519081016040528092919081815260200182805461031690610d07565b80156103635780601f1061033857610100808354040283529160200191610363565b820191906000526020600020905b81548152906001019060200180831161034657829003601f168201915b5050505050908060020154908060030154908060040160009054906101000a900460ff16908060040160019054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905086565b6000600160008381526020019081526020016000206040518060c0016040529081600082015481526020016001820180546103ec90610d07565b80601f016020809104026020016040519081016040528092919081815260200182805461041890610d07565b80156104655780601f1061043a57610100808354040283529160200191610465565b820191906000526020600020905b81548152906001019060200180831161044857829003601f168201915b5050505050815260200160028201548152602001600382015481526020016004820160009054906101000a900460ff161515151581526020016004820160019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815250509050806060015134101561053c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161053390610d85565b60405180910390fd5b60008211801561054e57506000548211155b61058d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161058490610df1565b60405180910390fd5b6001151581608001511515146105d8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105cf90610e83565b60405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166323b872dd8260a001513384604001516040518463ffffffff1660e01b815260040161063d93929190610ee5565b600060405180830381600087803b15801561065757600080fd5b505af115801561066b573d6000803e3d6000fd5b50505050600081608001901515908115158152505060008160a0015173ffffffffffffffffffffffffffffffffffffffff16346040516106aa90610f4d565b60006040518083038185875af1925050503d80600081146106e7576040519150601f19603f3d011682016040523d82523d6000602084013e6106ec565b606091505b5050905080610730576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161072790610fae565b60405180910390fd5b505050565b82805461074190610d07565b90600052602060002090601f01602090048101928261076357600085556107aa565b82601f1061077c57805160ff19168380011785556107aa565b828001600101855582156107aa579182015b828111156107a957825182559160200191906001019061078e565b5b5090506107b791906107bb565b5090565b5b808211156107d45760008160009055506001016107bc565b5090565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61083f826107f6565b810181811067ffffffffffffffff8211171561085e5761085d610807565b5b80604052505050565b60006108716107d8565b905061087d8282610836565b919050565b600067ffffffffffffffff82111561089d5761089c610807565b5b6108a6826107f6565b9050602081019050919050565b82818337600083830152505050565b60006108d56108d084610882565b610867565b9050828152602081018484840111156108f1576108f06107f1565b5b6108fc8482856108b3565b509392505050565b600082601f830112610919576109186107ec565b5b81356109298482602086016108c2565b91505092915050565b6000819050919050565b61094581610932565b811461095057600080fd5b50565b6000813590506109628161093c565b92915050565b600080600060608486031215610981576109806107e2565b5b600084013567ffffffffffffffff81111561099f5761099e6107e7565b5b6109ab86828701610904565b93505060206109bc86828701610953565b92505060406109cd86828701610953565b9150509250925092565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b6000610a1c610a17610a12846109d7565b6109f7565b6109d7565b9050919050565b6000610a2e82610a01565b9050919050565b6000610a4082610a23565b9050919050565b610a5081610a35565b82525050565b6000602082019050610a6b6000830184610a47565b92915050565b610a7a81610932565b82525050565b6000602082019050610a956000830184610a71565b92915050565b600060208284031215610ab157610ab06107e2565b5b6000610abf84828501610953565b91505092915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610b02578082015181840152602081019050610ae7565b83811115610b11576000848401525b50505050565b6000610b2282610ac8565b610b2c8185610ad3565b9350610b3c818560208601610ae4565b610b45816107f6565b840191505092915050565b60008115159050919050565b610b6581610b50565b82525050565b6000610b76826109d7565b9050919050565b610b8681610b6b565b82525050565b600060c082019050610ba16000830189610a71565b8181036020830152610bb38188610b17565b9050610bc26040830187610a71565b610bcf6060830186610a71565b610bdc6080830185610b5c565b610be960a0830184610b7d565b979650505050505050565b7f50726963652073686f756c642062652067726561746572207468616e20300000600082015250565b6000610c2a601e83610ad3565b9150610c3582610bf4565b602082019050919050565b60006020820190508181036000830152610c5981610c1d565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000610c9a82610932565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415610ccd57610ccc610c60565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680610d1f57607f821691505b60208210811415610d3357610d32610cd8565b5b50919050565b7f50726963652073656e74206973206e6f7420636f727265637400000000000000600082015250565b6000610d6f601983610ad3565b9150610d7a82610d39565b602082019050919050565b60006020820190508181036000830152610d9e81610d62565b9050919050565b7f57726f6e67206974656d49640000000000000000000000000000000000000000600082015250565b6000610ddb600c83610ad3565b9150610de682610da5565b602082019050919050565b60006020820190508181036000830152610e0a81610dce565b9050919050565b7f54686973206974656d20697320686173206e6f74206265656e206c697374656460008201527f20666f722073616c650000000000000000000000000000000000000000000000602082015250565b6000610e6d602983610ad3565b9150610e7882610e11565b604082019050919050565b60006020820190508181036000830152610e9c81610e60565b9050919050565b6000610eae82610a23565b9050919050565b610ebe81610ea3565b82525050565b6000610ecf826109d7565b9050919050565b610edf81610ec4565b82525050565b6000606082019050610efa6000830186610eb5565b610f076020830185610ed6565b610f146040830184610a71565b949350505050565b600081905092915050565b50565b6000610f37600083610f1c565b9150610f4282610f27565b600082019050919050565b6000610f5882610f2a565b9150819050919050565b7f4661696c656420746f2073656e64204574686572000000000000000000000000600082015250565b6000610f98601483610ad3565b9150610fa382610f62565b602082019050919050565b60006020820190508181036000830152610fc781610f8b565b905091905056fea264697066735822122035ab2381eb274c7683087087db95cf6b903e0179982cf52dae6308eb8a7f16fa64736f6c63430008090033", 123 | "deployedBytecode": "0x60806040526004361061004e5760003560e01c80634783de501461005a5780636881e763146100835780636bfb0d01146100ae578063bfb231d2146100d9578063f3eee3851461011b57610055565b3661005557005b600080fd5b34801561006657600080fd5b50610081600480360381019061007c9190610968565b610137565b005b34801561008f57600080fd5b50610098610297565b6040516100a59190610a56565b60405180910390f35b3480156100ba57600080fd5b506100c36102bb565b6040516100d09190610a80565b60405180910390f35b3480156100e557600080fd5b5061010060048036038101906100fb9190610a9b565b6102c1565b60405161011296959493929190610b8c565b60405180910390f35b61013560048036038101906101309190610a9b565b6103b2565b005b6000811161017a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161017190610c40565b60405180910390fd5b60008081548092919061018c90610c8f565b91905055506040518060c0016040528060005481526020018481526020018381526020018281526020016001151581526020013373ffffffffffffffffffffffffffffffffffffffff168152506001600080548152602001908152602001600020600082015181600001556020820151816001019080519060200190610213929190610735565b50604082015181600201556060820151816003015560808201518160040160006101000a81548160ff02191690831515021790555060a08201518160040160016101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550905050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60005481565b60016020528060005260406000206000915090508060000154908060010180546102ea90610d07565b80601f016020809104026020016040519081016040528092919081815260200182805461031690610d07565b80156103635780601f1061033857610100808354040283529160200191610363565b820191906000526020600020905b81548152906001019060200180831161034657829003601f168201915b5050505050908060020154908060030154908060040160009054906101000a900460ff16908060040160019054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905086565b6000600160008381526020019081526020016000206040518060c0016040529081600082015481526020016001820180546103ec90610d07565b80601f016020809104026020016040519081016040528092919081815260200182805461041890610d07565b80156104655780601f1061043a57610100808354040283529160200191610465565b820191906000526020600020905b81548152906001019060200180831161044857829003601f168201915b5050505050815260200160028201548152602001600382015481526020016004820160009054906101000a900460ff161515151581526020016004820160019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815250509050806060015134101561053c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161053390610d85565b60405180910390fd5b60008211801561054e57506000548211155b61058d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161058490610df1565b60405180910390fd5b6001151581608001511515146105d8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105cf90610e83565b60405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166323b872dd8260a001513384604001516040518463ffffffff1660e01b815260040161063d93929190610ee5565b600060405180830381600087803b15801561065757600080fd5b505af115801561066b573d6000803e3d6000fd5b50505050600081608001901515908115158152505060008160a0015173ffffffffffffffffffffffffffffffffffffffff16346040516106aa90610f4d565b60006040518083038185875af1925050503d80600081146106e7576040519150601f19603f3d011682016040523d82523d6000602084013e6106ec565b606091505b5050905080610730576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161072790610fae565b60405180910390fd5b505050565b82805461074190610d07565b90600052602060002090601f01602090048101928261076357600085556107aa565b82601f1061077c57805160ff19168380011785556107aa565b828001600101855582156107aa579182015b828111156107a957825182559160200191906001019061078e565b5b5090506107b791906107bb565b5090565b5b808211156107d45760008160009055506001016107bc565b5090565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61083f826107f6565b810181811067ffffffffffffffff8211171561085e5761085d610807565b5b80604052505050565b60006108716107d8565b905061087d8282610836565b919050565b600067ffffffffffffffff82111561089d5761089c610807565b5b6108a6826107f6565b9050602081019050919050565b82818337600083830152505050565b60006108d56108d084610882565b610867565b9050828152602081018484840111156108f1576108f06107f1565b5b6108fc8482856108b3565b509392505050565b600082601f830112610919576109186107ec565b5b81356109298482602086016108c2565b91505092915050565b6000819050919050565b61094581610932565b811461095057600080fd5b50565b6000813590506109628161093c565b92915050565b600080600060608486031215610981576109806107e2565b5b600084013567ffffffffffffffff81111561099f5761099e6107e7565b5b6109ab86828701610904565b93505060206109bc86828701610953565b92505060406109cd86828701610953565b9150509250925092565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b6000610a1c610a17610a12846109d7565b6109f7565b6109d7565b9050919050565b6000610a2e82610a01565b9050919050565b6000610a4082610a23565b9050919050565b610a5081610a35565b82525050565b6000602082019050610a6b6000830184610a47565b92915050565b610a7a81610932565b82525050565b6000602082019050610a956000830184610a71565b92915050565b600060208284031215610ab157610ab06107e2565b5b6000610abf84828501610953565b91505092915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610b02578082015181840152602081019050610ae7565b83811115610b11576000848401525b50505050565b6000610b2282610ac8565b610b2c8185610ad3565b9350610b3c818560208601610ae4565b610b45816107f6565b840191505092915050565b60008115159050919050565b610b6581610b50565b82525050565b6000610b76826109d7565b9050919050565b610b8681610b6b565b82525050565b600060c082019050610ba16000830189610a71565b8181036020830152610bb38188610b17565b9050610bc26040830187610a71565b610bcf6060830186610a71565b610bdc6080830185610b5c565b610be960a0830184610b7d565b979650505050505050565b7f50726963652073686f756c642062652067726561746572207468616e20300000600082015250565b6000610c2a601e83610ad3565b9150610c3582610bf4565b602082019050919050565b60006020820190508181036000830152610c5981610c1d565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000610c9a82610932565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415610ccd57610ccc610c60565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680610d1f57607f821691505b60208210811415610d3357610d32610cd8565b5b50919050565b7f50726963652073656e74206973206e6f7420636f727265637400000000000000600082015250565b6000610d6f601983610ad3565b9150610d7a82610d39565b602082019050919050565b60006020820190508181036000830152610d9e81610d62565b9050919050565b7f57726f6e67206974656d49640000000000000000000000000000000000000000600082015250565b6000610ddb600c83610ad3565b9150610de682610da5565b602082019050919050565b60006020820190508181036000830152610e0a81610dce565b9050919050565b7f54686973206974656d20697320686173206e6f74206265656e206c697374656460008201527f20666f722073616c650000000000000000000000000000000000000000000000602082015250565b6000610e6d602983610ad3565b9150610e7882610e11565b604082019050919050565b60006020820190508181036000830152610e9c81610e60565b9050919050565b6000610eae82610a23565b9050919050565b610ebe81610ea3565b82525050565b6000610ecf826109d7565b9050919050565b610edf81610ec4565b82525050565b6000606082019050610efa6000830186610eb5565b610f076020830185610ed6565b610f146040830184610a71565b949350505050565b600081905092915050565b50565b6000610f37600083610f1c565b9150610f4282610f27565b600082019050919050565b6000610f5882610f2a565b9150819050919050565b7f4661696c656420746f2073656e64204574686572000000000000000000000000600082015250565b6000610f98601483610ad3565b9150610fa382610f62565b602082019050919050565b60006020820190508181036000830152610fc781610f8b565b905091905056fea264697066735822122035ab2381eb274c7683087087db95cf6b903e0179982cf52dae6308eb8a7f16fa64736f6c63430008090033", 124 | "linkReferences": {}, 125 | "deployedLinkReferences": {} 126 | } --------------------------------------------------------------------------------