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  }