Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ioctl][ioid][#1] ioid sub commands #4284

Merged
merged 10 commits into from
May 30, 2024
Merged
222 changes: 222 additions & 0 deletions ioctl/cmd/ioid/applyioid.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
package ioid

import (
"encoding/hex"
"math/big"
"strings"

"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/iotexproject/iotex-address/address"
"github.com/iotexproject/iotex-core/ioctl/cmd/action"
"github.com/iotexproject/iotex-core/ioctl/config"
"github.com/iotexproject/iotex-core/ioctl/output"
"github.com/spf13/cobra"
)

// Multi-language support
var (
_applyUsages = map[config.Language]string{
config.English: "apply",
config.Chinese: "apply",
}
_applyShorts = map[config.Language]string{
config.English: "Apply ioIDs",
config.Chinese: "申请 ioID",
}
_ioIDStoreUsages = map[config.Language]string{
config.English: "ioID store contract address",
config.Chinese: "ioID Store 合约地址",
}
_projectIdUsages = map[config.Language]string{
config.English: "project id",
config.Chinese: "项目Id",
}
_amountUsages = map[config.Language]string{
config.English: "amount",
config.Chinese: "数量",
}
)

// _applyCmd represents the ioID apply command
var _applyCmd = &cobra.Command{
Use: config.TranslateInLang(_applyUsages, config.UILanguage),
Short: config.TranslateInLang(_applyShorts, config.UILanguage),
Args: cobra.MinimumNArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
err := apply()
return output.PrintError(err)
},
}

var (
ioIDStore string
projectId uint64
amount uint64
ioIDStoreABI = `[
{
"inputs": [],
"name": "price",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "project",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "projectAppliedAmount",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "projectActivedAmount",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "projectDeviceContract",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_projectId",
"type": "uint256"
},
{
"internalType": "address",
"name": "_contract",
"type": "address"
}
],
"name": "setDeviceContract",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_projectId",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "_amount",
"type": "uint256"
}
],
"name": "applyIoIDs",
"outputs": [],
"stateMutability": "payable",
"type": "function"
}
]`
)

func init() {
_applyCmd.Flags().StringVarP(
&ioIDStore, "ioIDStore", "i",
"0xA0C9f9A884cdAE649a42F16b057735Bc4fE786CD",
config.TranslateInLang(_ioIDStoreUsages, config.UILanguage),
)
_applyCmd.Flags().Uint64VarP(
&projectId, "projectId", "p", 0,
config.TranslateInLang(_projectIdUsages, config.UILanguage),
)
_applyCmd.Flags().Uint64VarP(
&amount, "amount", "a", 1,
config.TranslateInLang(_amountUsages, config.UILanguage),
)
}

func apply() error {
ioioIDStore, err := address.FromHex(ioIDStore)
if err != nil {
return output.NewError(output.AddressError, "failed to convert ioIDStore address", err)
}

ioIDStoreAbi, err := abi.JSON(strings.NewReader(ioIDStoreABI))
if err != nil {
return output.NewError(output.SerializationError, "failed to unmarshal abi", err)
}

data, err := ioIDStoreAbi.Pack("price")
if err != nil {
return output.NewError(output.ConvertError, "failed to pack price arguments", err)
}
priceHex, err := action.Read(ioioIDStore, "0", data)
if err != nil {
return output.NewError(output.APIError, "failed to read contract", err)
}
price, _ := hex.DecodeString(priceHex)
total := new(big.Int).Mul(new(big.Int).SetBytes(price), new(big.Int).SetUint64(amount))

data, err = ioIDStoreAbi.Pack("applyIoIDs", new(big.Int).SetUint64(projectId), new(big.Int).SetUint64(amount))
if err != nil {
return output.NewError(output.ConvertError, "failed to pack apply arguments", err)
}

return action.Execute(ioioIDStore.String(), total, data)
}
83 changes: 83 additions & 0 deletions ioctl/cmd/ioid/ioid.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package ioid

import (
"context"
"time"

"github.com/cenkalti/backoff"
"github.com/grpc-ecosystem/go-grpc-middleware/util/metautils"
"github.com/iotexproject/iotex-core/ioctl/config"
"github.com/iotexproject/iotex-core/ioctl/output"
"github.com/iotexproject/iotex-core/ioctl/util"
"github.com/iotexproject/iotex-proto/golang/iotexapi"
"github.com/spf13/cobra"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)

// Multi-language support
var (
_ioIDCmdShorts = map[config.Language]string{
config.English: "Manage ioID",
config.Chinese: "管理 ioID",
}
_flagInsEndPointUsages = map[config.Language]string{
config.English: "set endpoint for once",
config.Chinese: "一次设置端点", // this translation
}
_flagInsInsecureUsages = map[config.Language]string{
config.English: "insecure connection for once",
config.Chinese: "一次不安全连接", // this translation
}
)

// IoIDCmd represents the ins command
var IoIDCmd = &cobra.Command{
Use: "ioid",
Short: config.TranslateInLang(_ioIDCmdShorts, config.UILanguage),
}

func init() {
IoIDCmd.AddCommand(_projectRegisterCmd)
IoIDCmd.AddCommand(_applyCmd)
IoIDCmd.AddCommand(_projectCmd)
IoIDCmd.AddCommand(_deviceCmd)
IoIDCmd.PersistentFlags().StringVar(&config.ReadConfig.Endpoint, "endpoint",
config.ReadConfig.Endpoint, config.TranslateInLang(_flagInsEndPointUsages,
config.UILanguage))
IoIDCmd.PersistentFlags().BoolVar(&config.Insecure, "insecure", config.Insecure,
config.TranslateInLang(_flagInsInsecureUsages, config.UILanguage))
}

func waitReceiptByActionHash(h string) (*iotexapi.GetReceiptByActionResponse, error) {
conn, err := util.ConnectToEndpoint(config.ReadConfig.SecureConnect && !config.Insecure)
if err != nil {
return nil, output.NewError(output.NetworkError, "failed to connect to endpoint", err)
}
defer conn.Close()
cli := iotexapi.NewAPIServiceClient(conn)
ctx := context.Background()

jwtMD, err := util.JwtAuth()
if err == nil {
ctx = metautils.NiceMD(jwtMD).ToOutgoing(ctx)
}

var rsp *iotexapi.GetReceiptByActionResponse
err = backoff.Retry(func() error {
rsp, err = cli.GetReceiptByAction(ctx, &iotexapi.GetReceiptByActionRequest{
ActionHash: h,
})
return err
}, backoff.WithMaxRetries(backoff.NewConstantBackOff(30*time.Second), 3))
if err != nil {
sta, ok := status.FromError(err)
if ok && sta.Code() == codes.NotFound {
return nil, output.NewError(output.APIError, "not found", nil)
} else if ok {
return nil, output.NewError(output.APIError, sta.Message(), nil)
}
return nil, output.NewError(output.NetworkError, "failed to invoke GetReceiptByAction api", err)
}
return rsp, nil
}
Loading
Loading