github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/contracts/ens/ens.go (about) 1 // Copyright 2016 The Spectrum Authors 2 // This file is part of the Spectrum library. 3 // 4 // The Spectrum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The Spectrum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the Spectrum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package ens 18 19 //go:generate abigen --sol contract/ens.sol --pkg contract --out contract/ens.go 20 21 import ( 22 "math/big" 23 "strings" 24 25 "github.com/SmartMeshFoundation/Spectrum/accounts/abi/bind" 26 "github.com/SmartMeshFoundation/Spectrum/common" 27 "github.com/SmartMeshFoundation/Spectrum/contracts/ens/contract" 28 "github.com/SmartMeshFoundation/Spectrum/core/types" 29 "github.com/SmartMeshFoundation/Spectrum/crypto" 30 ) 31 32 var ( 33 MainNetAddress = common.HexToAddress("0x314159265dD8dbb310642f98f50C066173C1259b") 34 TestNetAddress = common.HexToAddress("0x112234455c3a32fd11230c42e7bccd4a84e02010") 35 ) 36 37 // swarm domain name registry and resolver 38 type ENS struct { 39 *contract.ENSSession 40 contractBackend bind.ContractBackend 41 } 42 43 // NewENS creates a struct exposing convenient high-level operations for interacting with 44 // the Ethereum Name Service. 45 func NewENS(transactOpts *bind.TransactOpts, contractAddr common.Address, contractBackend bind.ContractBackend) (*ENS, error) { 46 ens, err := contract.NewENS(contractAddr, contractBackend) 47 if err != nil { 48 return nil, err 49 } 50 51 return &ENS{ 52 &contract.ENSSession{ 53 Contract: ens, 54 TransactOpts: *transactOpts, 55 }, 56 contractBackend, 57 }, nil 58 } 59 60 // DeployENS deploys an instance of the ENS nameservice, with a 'first-in, first-served' root registrar. 61 func DeployENS(transactOpts *bind.TransactOpts, contractBackend bind.ContractBackend) (*ENS, error) { 62 // Deploy the ENS registry 63 ensAddr, _, _, err := contract.DeployENS(transactOpts, contractBackend, transactOpts.From) 64 if err != nil { 65 return nil, err 66 } 67 68 ens, err := NewENS(transactOpts, ensAddr, contractBackend) 69 if err != nil { 70 return nil, err 71 } 72 73 // Deploy the registrar 74 regAddr, _, _, err := contract.DeployFIFSRegistrar(transactOpts, contractBackend, ensAddr, [32]byte{}) 75 if err != nil { 76 return nil, err 77 } 78 79 // Set the registrar as owner of the ENS root 80 _, err = ens.SetOwner([32]byte{}, regAddr) 81 if err != nil { 82 return nil, err 83 } 84 85 return ens, nil 86 } 87 88 func ensParentNode(name string) (common.Hash, common.Hash) { 89 parts := strings.SplitN(name, ".", 2) 90 label := crypto.Keccak256Hash([]byte(parts[0])) 91 if len(parts) == 1 { 92 return [32]byte{}, label 93 } else { 94 parentNode, parentLabel := ensParentNode(parts[1]) 95 return crypto.Keccak256Hash(parentNode[:], parentLabel[:]), label 96 } 97 } 98 99 func ensNode(name string) common.Hash { 100 parentNode, parentLabel := ensParentNode(name) 101 return crypto.Keccak256Hash(parentNode[:], parentLabel[:]) 102 } 103 104 func (self *ENS) getResolver(node [32]byte) (*contract.PublicResolverSession, error) { 105 resolverAddr, err := self.Resolver(node) 106 if err != nil { 107 return nil, err 108 } 109 110 resolver, err := contract.NewPublicResolver(resolverAddr, self.contractBackend) 111 if err != nil { 112 return nil, err 113 } 114 115 return &contract.PublicResolverSession{ 116 Contract: resolver, 117 TransactOpts: self.TransactOpts, 118 }, nil 119 } 120 121 func (self *ENS) getRegistrar(node [32]byte) (*contract.FIFSRegistrarSession, error) { 122 registrarAddr, err := self.Owner(node) 123 if err != nil { 124 return nil, err 125 } 126 127 registrar, err := contract.NewFIFSRegistrar(registrarAddr, self.contractBackend) 128 if err != nil { 129 return nil, err 130 } 131 132 return &contract.FIFSRegistrarSession{ 133 Contract: registrar, 134 TransactOpts: self.TransactOpts, 135 }, nil 136 } 137 138 // Resolve is a non-transactional call that returns the content hash associated with a name. 139 func (self *ENS) Resolve(name string) (common.Hash, error) { 140 node := ensNode(name) 141 142 resolver, err := self.getResolver(node) 143 if err != nil { 144 return common.Hash{}, err 145 } 146 147 ret, err := resolver.Content(node) 148 if err != nil { 149 return common.Hash{}, err 150 } 151 152 return common.BytesToHash(ret[:]), nil 153 } 154 155 // Register registers a new domain name for the caller, making them the owner of the new name. 156 // Only works if the registrar for the parent domain implements the FIFS registrar protocol. 157 func (self *ENS) Register(name string) (*types.Transaction, error) { 158 parentNode, label := ensParentNode(name) 159 160 registrar, err := self.getRegistrar(parentNode) 161 if err != nil { 162 return nil, err 163 } 164 165 opts := self.TransactOpts 166 opts.GasLimit = big.NewInt(200000) 167 return registrar.Contract.Register(&opts, label, self.TransactOpts.From) 168 } 169 170 // SetContentHash sets the content hash associated with a name. Only works if the caller 171 // owns the name, and the associated resolver implements a `setContent` function. 172 func (self *ENS) SetContentHash(name string, hash common.Hash) (*types.Transaction, error) { 173 node := ensNode(name) 174 175 resolver, err := self.getResolver(node) 176 if err != nil { 177 return nil, err 178 } 179 180 opts := self.TransactOpts 181 opts.GasLimit = big.NewInt(200000) 182 return resolver.Contract.SetContent(&opts, node, hash) 183 }