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  }