status-go/vendor/github.com/wealdtech/go-ens/v3/name.go

315 lines
9.5 KiB
Go
Raw Normal View History

// Copyright 2017-2019 Weald Technology Trading
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package ens
import (
"crypto/rand"
"errors"
"fmt"
"math/big"
"time"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
)
// Name represents an ENS name, for example 'foo.bar.eth'.
type Name struct {
backend bind.ContractBackend
// Name is the fully-qualified name of an ENS domain e.g. foo.bar.eth
Name string
// Domain is the domain of an ENS domain e.g. bar.eth
Domain string
// Label is the name part of an ENS domain e.g. foo
Label string
// Contracts
registry *Registry
registrar *BaseRegistrar
controller *ETHController
}
// NewName creates an ENS name structure.
// Note that this does not create the name on-chain.
func NewName(backend bind.ContractBackend, name string) (*Name, error) {
name, err := NormaliseDomain(name)
if err != nil {
return nil, err
}
domain := Domain(name)
label, err := DomainPart(name, 1)
if err != nil {
return nil, err
}
registry, err := NewRegistry(backend)
if err != nil {
return nil, err
}
registrar, err := NewBaseRegistrar(backend, domain)
if err != nil {
return nil, err
}
controller, err := NewETHController(backend, domain)
if err != nil {
return nil, err
}
isValid, err := controller.IsValid(name)
if err != nil {
return nil, err
}
if !isValid {
return nil, errors.New("name is not valid according to the rules of the registrar (too short, invalid characters, etc.)")
}
return &Name{
backend: backend,
Name: name,
Domain: domain,
Label: label,
registry: registry,
registrar: registrar,
controller: controller,
}, nil
}
// IsRegistered returns true if the name is registered in the registrar
func (n *Name) IsRegistered() (bool, error) {
registrant, err := n.Registrant()
if err != nil {
return false, err
}
return registrant != UnknownAddress, nil
}
// ExtendRegistration sends a transaction that extends the registration of the name.
func (n *Name) ExtendRegistration(opts *bind.TransactOpts) (*types.Transaction, error) {
isRegistered, err := n.IsRegistered()
if err != nil {
return nil, err
}
if !isRegistered {
return nil, errors.New("name is not registered")
}
rentCost, err := n.RentCost()
if err != nil {
return nil, err
}
if opts.Value == nil || opts.Value.Cmp(rentCost) < 0 {
return nil, errors.New("not enough funds to extend the registration")
}
return n.controller.Renew(opts, n.Name)
}
// RegistrationInterval obtains the minimum interval between commit and reveal
// when registering this name.
func (n *Name) RegistrationInterval() (time.Duration, error) {
interval, err := n.controller.MinCommitmentInterval()
if err != nil {
return time.Duration(0), err
}
return time.Duration(interval.Int64()) * time.Second, nil
}
// RegisterStageOne sends a transaction that starts the registration process.
func (n *Name) RegisterStageOne(registrant common.Address, opts *bind.TransactOpts) (*types.Transaction, [32]byte, error) {
var secret [32]byte
_, err := rand.Read(secret[:])
if err != nil {
return nil, secret, err
}
isRegistered, err := n.IsRegistered()
if err != nil {
return nil, secret, err
}
if isRegistered {
return nil, secret, errors.New("name is already registered")
}
signedTx, err := n.controller.Commit(opts, n.Label, registrant, secret)
return signedTx, secret, err
}
// RegisterStageTwo sends a transaction that completes the registration process.
// The registrant must be the same as supplied in RegisterStageOne.
// The secret is that returned by RegisterStageOne.
// At least RegistrationInterval() time must have passed since the stage one
// transaction was mined for this to work.
func (n *Name) RegisterStageTwo(registrant common.Address, secret [32]byte, opts *bind.TransactOpts) (*types.Transaction, error) {
commitTS, err := n.controller.CommitmentTime(n.Label, registrant, secret)
if err != nil {
return nil, err
}
if commitTS.Cmp(big.NewInt(0)) == 0 {
return nil, errors.New("stage 2 attempted prior to successful stage 1 transaction")
}
commit := time.Unix(commitTS.Int64(), 0)
minCommitIntervalTS, err := n.controller.MinCommitmentInterval()
if err != nil {
return nil, err
}
minCommitInterval := time.Duration(minCommitIntervalTS.Int64()) * time.Second
minStageTwoTime := commit.Add(minCommitInterval)
if time.Now().Before(minStageTwoTime) {
return nil, errors.New("too early to send second transaction")
}
maxCommitIntervalTS, err := n.controller.MaxCommitmentInterval()
if err != nil {
return nil, err
}
maxCommitInterval := time.Duration(maxCommitIntervalTS.Int64()) * time.Second
maxStageTwoTime := commit.Add(maxCommitInterval)
if time.Now().After(maxStageTwoTime) {
return nil, errors.New("too late to send second transaction")
}
return n.controller.Reveal(opts, n.Label, registrant, secret)
}
// Expires obtain the time at which the registration for this name expires.
func (n *Name) Expires() (time.Time, error) {
expiryTS, err := n.registrar.Expiry(n.Label)
if err != nil {
return time.Unix(0, 0), err
}
if expiryTS.Int64() == 0 {
return time.Unix(0, 0), errors.New("not registered")
}
return time.Unix(expiryTS.Int64(), 0), nil
}
// Controller obtains the controller for this name.
// The controller can carry out operations on the name such as setting
// records, but cannot transfer ultimate ownership of the name.
func (n *Name) Controller() (common.Address, error) {
return n.registry.Owner(n.Name)
}
// SetController sets the controller for this name.
// The controller can carry out operations on the name such as setting
// records, but cannot transfer ultimate ownership of the name.
func (n *Name) SetController(controller common.Address, opts *bind.TransactOpts) (*types.Transaction, error) {
// Are we the current controller?
curController, err := n.Controller()
if err != nil {
return nil, err
}
if curController == opts.From {
return n.registry.SetOwner(opts, n.Name, controller)
}
// Perhaps we are the registrant
registrant, err := n.Registrant()
if err != nil {
return nil, err
}
// Are we actually trying to reclaim?
if registrant == opts.From && registrant == controller {
return n.Reclaim(opts)
}
return nil, errors.New("not authorised to change the controller")
}
// Reclaim reclaims controller rights by the registrant
func (n *Name) Reclaim(opts *bind.TransactOpts) (*types.Transaction, error) {
// Ensure the we are the registrant
registrant, err := n.Registrant()
if err != nil {
return nil, err
}
if registrant != opts.From {
return nil, errors.New("not the registrant")
}
return n.registrar.Reclaim(opts, n.Name, registrant)
}
// Registrant obtains the registrant for this name.
func (n *Name) Registrant() (common.Address, error) {
return n.registrar.Owner(n.Label)
}
// Transfer transfers the registration of this name to a new registrant.
func (n *Name) Transfer(registrant common.Address, opts *bind.TransactOpts) (*types.Transaction, error) {
// Ensure the we are the registrant
currentRegistrant, err := n.Registrant()
if err != nil {
return nil, err
}
if currentRegistrant != opts.From {
return nil, errors.New("not the current registrant")
}
return n.registrar.SetOwner(opts, n.Label, registrant)
}
// RentCost returns the cost of rent in Wei-per-second.
func (n *Name) RentCost() (*big.Int, error) {
return n.controller.RentCost(n.Label)
}
// CreateSubdomain creates a subdomain on the name.
func (n *Name) CreateSubdomain(label string, controller common.Address, opts *bind.TransactOpts) (*types.Transaction, error) {
// Confirm the subdomain does not already exist
fqdn := fmt.Sprintf("%s.%s", label, n.Name)
subdomainController, err := n.registry.Owner(fqdn)
if err != nil {
return nil, err
}
if subdomainController != UnknownAddress {
return nil, errors.New("that subdomain already exists")
}
return n.registry.SetSubdomainOwner(opts, n.Name, label, controller)
}
// ResolverAddress fetches the address of the resolver contract for the name.
func (n *Name) ResolverAddress() (common.Address, error) {
return n.registry.ResolverAddress(n.Name)
}
// SetResolverAddress sets the resolver contract address for the name.
func (n *Name) SetResolverAddress(address common.Address, opts *bind.TransactOpts) (*types.Transaction, error) {
return n.registry.SetResolver(opts, n.Name, address)
}
// Address fetches the address of the name for a given coin type.
// Coin types are defined at https://github.com/satoshilabs/slips/blob/master/slip-0044.md
func (n *Name) Address(coinType uint64) ([]byte, error) {
resolver, err := NewResolver(n.backend, n.Name)
if err != nil {
return nil, err
}
return resolver.MultiAddress(coinType)
}
// SetAddress sets the address of the name for a given coin type.
// Coin types are defined at https://github.com/satoshilabs/slips/blob/master/slip-0044.md
func (n *Name) SetAddress(coinType uint64, address []byte, opts *bind.TransactOpts) (*types.Transaction, error) {
resolver, err := NewResolver(n.backend, n.Name)
if err != nil {
return nil, err
}
return resolver.SetMultiAddress(opts, coinType, address)
}