github.com/daeglee/go-ethereum@v0.0.0-20190504220456-cad3e8d18e9b/contracts/ens/ens.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum 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 go-ethereum 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 go-ethereum 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 //go:generate abigen --sol contract/ENSRegistry.sol --exc contract/ENS.sol:ENS --pkg contract --out contract/ensregistry.go 21 //go:generate abigen --sol contract/FIFSRegistrar.sol --exc contract/ENS.sol:ENS --pkg contract --out contract/fifsregistrar.go 22 //go:generate abigen --sol contract/PublicResolver.sol --exc contract/ENS.sol:ENS --pkg contract --out contract/publicresolver.go 23 24 import ( 25 "encoding/binary" 26 "strings" 27 28 "github.com/ethereum/go-ethereum/accounts/abi/bind" 29 "github.com/ethereum/go-ethereum/common" 30 "github.com/ethereum/go-ethereum/contracts/ens/contract" 31 "github.com/ethereum/go-ethereum/contracts/ens/fallback_contract" 32 "github.com/ethereum/go-ethereum/core/types" 33 "github.com/ethereum/go-ethereum/crypto" 34 ) 35 36 var ( 37 MainNetAddress = common.HexToAddress("0x314159265dD8dbb310642f98f50C066173C1259b") 38 TestNetAddress = common.HexToAddress("0x112234455c3a32fd11230c42e7bccd4a84e02010") 39 contentHash_Interface_Id [4]byte 40 ) 41 42 const contentHash_Interface_Id_Spec = 0xbc1c58d1 43 44 func init() { 45 binary.BigEndian.PutUint32(contentHash_Interface_Id[:], contentHash_Interface_Id_Spec) 46 } 47 48 // ENS is the swarm domain name registry and resolver 49 type ENS struct { 50 *contract.ENSSession 51 contractBackend bind.ContractBackend 52 } 53 54 // NewENS creates a struct exposing convenient high-level operations for interacting with 55 // the Ethereum Name Service. 56 func NewENS(transactOpts *bind.TransactOpts, contractAddr common.Address, contractBackend bind.ContractBackend) (*ENS, error) { 57 ens, err := contract.NewENS(contractAddr, contractBackend) 58 if err != nil { 59 return nil, err 60 } 61 return &ENS{ 62 &contract.ENSSession{ 63 Contract: ens, 64 TransactOpts: *transactOpts, 65 }, 66 contractBackend, 67 }, nil 68 } 69 70 // DeployENS deploys an instance of the ENS nameservice, with a 'first-in, first-served' root registrar. 71 func DeployENS(transactOpts *bind.TransactOpts, contractBackend bind.ContractBackend) (common.Address, *ENS, error) { 72 // Deploy the ENS registry 73 ensAddr, _, _, err := contract.DeployENSRegistry(transactOpts, contractBackend) 74 if err != nil { 75 return ensAddr, nil, err 76 } 77 ens, err := NewENS(transactOpts, ensAddr, contractBackend) 78 if err != nil { 79 return ensAddr, nil, err 80 } 81 // Deploy the registrar 82 regAddr, _, _, err := contract.DeployFIFSRegistrar(transactOpts, contractBackend, ensAddr, [32]byte{}) 83 if err != nil { 84 return ensAddr, nil, err 85 } 86 // Set the registrar as owner of the ENS root 87 if _, err = ens.SetOwner([32]byte{}, regAddr); err != nil { 88 return ensAddr, nil, err 89 } 90 return ensAddr, ens, nil 91 } 92 93 func ensParentNode(name string) (common.Hash, common.Hash) { 94 parts := strings.SplitN(name, ".", 2) 95 label := crypto.Keccak256Hash([]byte(parts[0])) 96 if len(parts) == 1 { 97 return [32]byte{}, label 98 } 99 parentNode, parentLabel := ensParentNode(parts[1]) 100 return crypto.Keccak256Hash(parentNode[:], parentLabel[:]), label 101 } 102 103 func EnsNode(name string) common.Hash { 104 parentNode, parentLabel := ensParentNode(name) 105 return crypto.Keccak256Hash(parentNode[:], parentLabel[:]) 106 } 107 108 func (ens *ENS) getResolver(node [32]byte) (*contract.PublicResolverSession, error) { 109 resolverAddr, err := ens.Resolver(node) 110 if err != nil { 111 return nil, err 112 } 113 resolver, err := contract.NewPublicResolver(resolverAddr, ens.contractBackend) 114 if err != nil { 115 return nil, err 116 } 117 return &contract.PublicResolverSession{ 118 Contract: resolver, 119 TransactOpts: ens.TransactOpts, 120 }, nil 121 } 122 123 func (ens *ENS) getFallbackResolver(node [32]byte) (*fallback_contract.PublicResolverSession, error) { 124 resolverAddr, err := ens.Resolver(node) 125 if err != nil { 126 return nil, err 127 } 128 resolver, err := fallback_contract.NewPublicResolver(resolverAddr, ens.contractBackend) 129 if err != nil { 130 return nil, err 131 } 132 return &fallback_contract.PublicResolverSession{ 133 Contract: resolver, 134 TransactOpts: ens.TransactOpts, 135 }, nil 136 } 137 138 func (ens *ENS) getRegistrar(node [32]byte) (*contract.FIFSRegistrarSession, error) { 139 registrarAddr, err := ens.Owner(node) 140 if err != nil { 141 return nil, err 142 } 143 registrar, err := contract.NewFIFSRegistrar(registrarAddr, ens.contractBackend) 144 if err != nil { 145 return nil, err 146 } 147 return &contract.FIFSRegistrarSession{ 148 Contract: registrar, 149 TransactOpts: ens.TransactOpts, 150 }, nil 151 } 152 153 // Resolve is a non-transactional call that returns the content hash associated with a name. 154 func (ens *ENS) Resolve(name string) (common.Hash, error) { 155 node := EnsNode(name) 156 157 resolver, err := ens.getResolver(node) 158 if err != nil { 159 return common.Hash{}, err 160 } 161 162 // IMPORTANT: The old contract is deprecated. This code should be removed latest on June 1st 2019 163 supported, err := resolver.SupportsInterface(contentHash_Interface_Id) 164 if err != nil { 165 return common.Hash{}, err 166 } 167 168 if !supported { 169 resolver, err := ens.getFallbackResolver(node) 170 if err != nil { 171 return common.Hash{}, err 172 } 173 ret, err := resolver.Content(node) 174 if err != nil { 175 return common.Hash{}, err 176 } 177 return common.BytesToHash(ret[:]), nil 178 } 179 180 // END DEPRECATED CODE 181 182 contentHash, err := resolver.Contenthash(node) 183 if err != nil { 184 return common.Hash{}, err 185 } 186 187 return extractContentHash(contentHash) 188 } 189 190 // Addr is a non-transactional call that returns the address associated with a name. 191 func (ens *ENS) Addr(name string) (common.Address, error) { 192 node := EnsNode(name) 193 194 resolver, err := ens.getResolver(node) 195 if err != nil { 196 return common.Address{}, err 197 } 198 ret, err := resolver.Addr(node) 199 if err != nil { 200 return common.Address{}, err 201 } 202 return common.BytesToAddress(ret[:]), nil 203 } 204 205 // SetAddress sets the address associated with a name. Only works if the caller 206 // owns the name, and the associated resolver implements a `setAddress` function. 207 func (ens *ENS) SetAddr(name string, addr common.Address) (*types.Transaction, error) { 208 node := EnsNode(name) 209 210 resolver, err := ens.getResolver(node) 211 if err != nil { 212 return nil, err 213 } 214 opts := ens.TransactOpts 215 opts.GasLimit = 200000 216 return resolver.Contract.SetAddr(&opts, node, addr) 217 } 218 219 // Register registers a new domain name for the caller, making them the owner of the new name. 220 // Only works if the registrar for the parent domain implements the FIFS registrar protocol. 221 func (ens *ENS) Register(name string) (*types.Transaction, error) { 222 parentNode, label := ensParentNode(name) 223 registrar, err := ens.getRegistrar(parentNode) 224 if err != nil { 225 return nil, err 226 } 227 return registrar.Contract.Register(&ens.TransactOpts, label, ens.TransactOpts.From) 228 } 229 230 // SetContentHash sets the content hash associated with a name. Only works if the caller 231 // owns the name, and the associated resolver implements a `setContenthash` function. 232 func (ens *ENS) SetContentHash(name string, hash []byte) (*types.Transaction, error) { 233 node := EnsNode(name) 234 235 resolver, err := ens.getResolver(node) 236 if err != nil { 237 return nil, err 238 } 239 240 opts := ens.TransactOpts 241 opts.GasLimit = 200000 242 243 // IMPORTANT: The old contract is deprecated. This code should be removed latest on June 1st 2019 244 supported, err := resolver.SupportsInterface(contentHash_Interface_Id) 245 if err != nil { 246 return nil, err 247 } 248 249 if !supported { 250 resolver, err := ens.getFallbackResolver(node) 251 if err != nil { 252 return nil, err 253 } 254 opts := ens.TransactOpts 255 opts.GasLimit = 200000 256 var b [32]byte 257 copy(b[:], hash) 258 return resolver.Contract.SetContent(&opts, node, b) 259 } 260 261 // END DEPRECATED CODE 262 return resolver.Contract.SetContenthash(&opts, node, hash) 263 }