github.com/iotexproject/iotex-core@v1.14.1-rc1/ioctl/cmd/ins/insregister.go (about)

     1  package ins
     2  
     3  import (
     4  	"encoding/hex"
     5  	"fmt"
     6  	"math/big"
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/ethereum/go-ethereum/accounts/abi"
    11  	"github.com/ethereum/go-ethereum/common"
    12  	"github.com/iotexproject/iotex-address/address"
    13  	"github.com/spf13/cobra"
    14  	"golang.org/x/crypto/sha3"
    15  
    16  	"github.com/iotexproject/iotex-core/ioctl/cmd/action"
    17  	"github.com/iotexproject/iotex-core/ioctl/config"
    18  	"github.com/iotexproject/iotex-core/ioctl/output"
    19  )
    20  
    21  // Multi-language support
    22  var (
    23  	_registerUsages = map[config.Language]string{
    24  		config.English: "register NAME",
    25  		config.Chinese: "register 名称",
    26  	}
    27  	_registerShorts = map[config.Language]string{
    28  		config.English: "Register INS name",
    29  		config.Chinese: "注册 INS 域名",
    30  	}
    31  	_registerControllerUsages = map[config.Language]string{
    32  		config.English: "controller contract address",
    33  		config.Chinese: "控制器合约地址",
    34  	}
    35  	_registerResolverUsages = map[config.Language]string{
    36  		config.English: "resolver contract address",
    37  		config.Chinese: "解析器合约地址",
    38  	}
    39  	_registerOwnerUsages = map[config.Language]string{
    40  		config.English: "name owner address",
    41  		config.Chinese: "域名 Owner 地址",
    42  	}
    43  )
    44  
    45  var (
    46  	duration   = big.NewInt(365 * 24 * 60 * 60)
    47  	secret     = [32]byte{}
    48  	controller string
    49  	resolver   string
    50  	owner      string
    51  
    52  	setAddrABI = `[
    53  		{
    54        "inputs": [
    55          {
    56            "internalType": "bytes32",
    57            "name": "node",
    58            "type": "bytes32"
    59          },
    60          {
    61            "internalType": "address",
    62            "name": "a",
    63            "type": "address"
    64          }
    65        ],
    66        "name": "setAddr",
    67        "outputs": [],
    68        "stateMutability": "nonpayable",
    69        "type": "function"
    70      }
    71  	]`
    72  	controllerABI = `[
    73  		{
    74        "inputs": [
    75          {
    76            "internalType": "bytes32",
    77            "name": "commitment",
    78            "type": "bytes32"
    79          }
    80        ],
    81        "name": "commit",
    82        "outputs": [],
    83        "stateMutability": "nonpayable",
    84        "type": "function"
    85      },
    86  		{
    87        "inputs": [
    88          {
    89            "internalType": "string",
    90            "name": "name",
    91            "type": "string"
    92          },
    93          {
    94            "internalType": "uint256",
    95            "name": "duration",
    96            "type": "uint256"
    97          }
    98        ],
    99        "name": "rentPrice",
   100        "outputs": [
   101          {
   102            "components": [
   103              {
   104                "internalType": "uint256",
   105                "name": "base",
   106                "type": "uint256"
   107              },
   108              {
   109                "internalType": "uint256",
   110                "name": "premium",
   111                "type": "uint256"
   112              }
   113            ],
   114            "internalType": "struct IPriceOracle.Price",
   115            "name": "price",
   116            "type": "tuple"
   117          }
   118        ],
   119        "stateMutability": "view",
   120        "type": "function"
   121      },
   122  		{
   123        "inputs": [
   124          {
   125            "internalType": "string",
   126            "name": "name",
   127            "type": "string"
   128          },
   129          {
   130            "internalType": "address",
   131            "name": "owner",
   132            "type": "address"
   133          },
   134          {
   135            "internalType": "uint256",
   136            "name": "duration",
   137            "type": "uint256"
   138          },
   139          {
   140            "internalType": "bytes32",
   141            "name": "secret",
   142            "type": "bytes32"
   143          },
   144          {
   145            "internalType": "address",
   146            "name": "resolver",
   147            "type": "address"
   148          },
   149          {
   150            "internalType": "bytes[]",
   151            "name": "data",
   152            "type": "bytes[]"
   153          },
   154          {
   155            "internalType": "bool",
   156            "name": "reverseRecord",
   157            "type": "bool"
   158          },
   159          {
   160            "internalType": "uint16",
   161            "name": "ownerControlledFuses",
   162            "type": "uint16"
   163          }
   164        ],
   165        "name": "register",
   166        "outputs": [],
   167        "stateMutability": "payable",
   168        "type": "function"
   169      }
   170  	]`
   171  )
   172  
   173  // _insRegisterCmd represents the action hash command
   174  var _insRegisterCmd = &cobra.Command{
   175  	Use:   config.TranslateInLang(_registerUsages, config.UILanguage),
   176  	Short: config.TranslateInLang(_registerShorts, config.UILanguage),
   177  	Args:  cobra.MinimumNArgs(1),
   178  	RunE: func(cmd *cobra.Command, args []string) error {
   179  		err := register(args)
   180  		return output.PrintError(err)
   181  	},
   182  }
   183  
   184  func init() {
   185  	_insRegisterCmd.Flags().StringVarP(
   186  		&controller, "controller", "c",
   187  		"0x8aA6acF9BFeEE0243578305706766065180E68d4",
   188  		config.TranslateInLang(_registerControllerUsages, config.UILanguage),
   189  	)
   190  	_insRegisterCmd.Flags().StringVarP(
   191  		&resolver, "resolver", "r",
   192  		"0x41B9132D4661E016A09a61B314a1DFc0038CE3e8",
   193  		config.TranslateInLang(_registerResolverUsages, config.UILanguage),
   194  	)
   195  	_insRegisterCmd.Flags().StringVarP(
   196  		&owner, "owner", "w",
   197  		"",
   198  		config.TranslateInLang(_registerOwnerUsages, config.UILanguage),
   199  	)
   200  
   201  	// init secret
   202  	sha := sha3.NewLegacyKeccak256()
   203  	sha.Write([]byte("secret"))
   204  	hash := sha.Sum(nil)
   205  	copy(secret[:], hash)
   206  }
   207  
   208  func makeCommitment(
   209  	name string,
   210  	owner common.Address,
   211  	duration *big.Int,
   212  	secret [32]byte,
   213  	data [][]byte,
   214  	reverseRecord bool,
   215  	ownerControlledFuses uint16,
   216  ) ([32]byte, error) {
   217  	resolver := common.HexToAddress(resolver)
   218  	sha := sha3.NewLegacyKeccak256()
   219  	sha.Write([]byte(name))
   220  	lable := [32]byte{}
   221  	copy(lable[:], sha.Sum(nil))
   222  
   223  	Bytes32, _ := abi.NewType("bytes32", "", nil)
   224  	Address, _ := abi.NewType("address", "", nil)
   225  	Uint256, _ := abi.NewType("uint256", "", nil)
   226  	BytesArray, _ := abi.NewType("bytes[]", "", nil)
   227  	Bool, _ := abi.NewType("bool", "", nil)
   228  	Uint16, _ := abi.NewType("uint16", "", nil)
   229  	args := abi.Arguments{
   230  		{Type: Bytes32, Name: "name"},
   231  		{Type: Address, Name: "owner"},
   232  		{Type: Uint256, Name: "duration"},
   233  		{Type: Bytes32, Name: "secret"},
   234  		{Type: Address, Name: "resolver"},
   235  		{Type: BytesArray, Name: "data"},
   236  		{Type: Bool, Name: "reverseRecord"},
   237  		{Type: Uint16, Name: "ownerControlledFuses"},
   238  	}
   239  
   240  	packed, err := args.Pack(lable, owner, duration, secret, resolver, data, reverseRecord, ownerControlledFuses)
   241  	if err != nil {
   242  		return [32]byte{}, err
   243  	}
   244  
   245  	hash := sha3.NewLegacyKeccak256()
   246  	hash.Write(packed)
   247  	result := [32]byte{}
   248  	copy(result[:], hash.Sum(nil))
   249  
   250  	return result, nil
   251  }
   252  
   253  func commit(name string, data []byte, ioController address.Address, controllerAbi abi.ABI) error {
   254  	commitment, err := makeCommitment(
   255  		name,
   256  		common.HexToAddress(owner),
   257  		duration,
   258  		secret,
   259  		[][]byte{data},
   260  		true,
   261  		0,
   262  	)
   263  	if err != nil {
   264  		return err
   265  	}
   266  	fmt.Printf("commit commitment for %s: %s ...\n", name, hex.EncodeToString(commitment[:]))
   267  
   268  	commitData, err := controllerAbi.Pack("commit", commitment)
   269  	if err != nil {
   270  		return output.NewError(output.ConvertError, "failed to pack commit arguments", err)
   271  	}
   272  	err = action.Execute(ioController.String(), big.NewInt(0), commitData)
   273  	if err != nil {
   274  		return output.NewError(output.UpdateError, "failed to commit commitment", err)
   275  	}
   276  	return nil
   277  }
   278  
   279  func register(args []string) error {
   280  	name := args[0]
   281  
   282  	if owner == "" {
   283  		signer, err := action.Signer()
   284  		if err != nil {
   285  			return output.NewError(output.AddressError, "failed to get signer address", err)
   286  		}
   287  		signerAddr, err := address.FromString(signer)
   288  		if err != nil {
   289  			return output.NewError(output.AddressError, "failed to convert signer address", err)
   290  		}
   291  		owner = signerAddr.Hex()
   292  	}
   293  
   294  	hash, err := nameHash(name)
   295  	if err != nil {
   296  		return output.NewError(output.SerializationError, "failed to compute namehash", err)
   297  	}
   298  
   299  	setAddrAbi, err := abi.JSON(strings.NewReader(setAddrABI))
   300  	if err != nil {
   301  		return output.NewError(output.SerializationError, "failed to unmarshal abi", err)
   302  	}
   303  	setAddrData, err := setAddrAbi.Pack("setAddr", hash, common.HexToAddress(owner))
   304  	if err != nil {
   305  		return output.NewError(output.ConvertError, "failed to pack setAddr arguments", err)
   306  	}
   307  
   308  	ioController, err := address.FromHex(controller)
   309  	if err != nil {
   310  		return output.NewError(output.AddressError, "failed to convert controller address", err)
   311  	}
   312  	controllerAbi, err := abi.JSON(strings.NewReader(controllerABI))
   313  	if err != nil {
   314  		return output.NewError(output.SerializationError, "failed to unmarshal abi", err)
   315  	}
   316  
   317  	if err = commit(name, setAddrData, ioController, controllerAbi); err != nil {
   318  		return err
   319  	}
   320  
   321  	fmt.Printf("sleep for activation commitment ...\n")
   322  	time.Sleep(60 * time.Second)
   323  
   324  	priceData, err := controllerAbi.Pack("rentPrice", name, duration)
   325  	if err != nil {
   326  		return output.NewError(output.ConvertError, "failed to pack price arguments", err)
   327  	}
   328  	priceHex, err := action.Read(ioController, "0", priceData)
   329  	if err != nil {
   330  		return output.NewError(output.APIError, "failed to read contract", err)
   331  	}
   332  	basePrice, _ := hex.DecodeString(priceHex[:64])
   333  	premiumPrice, _ := hex.DecodeString(priceHex[64:])
   334  	price := new(big.Int).Add(new(big.Int).SetBytes(basePrice), new(big.Int).SetBytes(premiumPrice))
   335  
   336  	registerData, err := controllerAbi.Pack(
   337  		"register",
   338  		name,
   339  		common.HexToAddress(owner),
   340  		duration,
   341  		secret,
   342  		common.HexToAddress(resolver),
   343  		[][]byte{setAddrData},
   344  		true,
   345  		uint16(0),
   346  	)
   347  	if err != nil {
   348  		return output.NewError(output.ConvertError, "failed to pack register arguments", err)
   349  	}
   350  
   351  	return action.Execute(ioController.String(), price, registerData)
   352  }