github.com/0chain/gosdk@v1.17.11/zcncore/mswallet_mobile.go (about)

     1  //go:build mobile
     2  // +build mobile
     3  
     4  package zcncore
     5  
     6  import (
     7  	"encoding/json"
     8  	"errors"
     9  	"fmt"
    10  	"strconv"
    11  
    12  	"github.com/0chain/gosdk/core/encryption"
    13  	"github.com/0chain/gosdk/core/zcncrypto"
    14  )
    15  
    16  type MultisigSCWallet interface {
    17  	GetClientID() string
    18  	GetSignatureScheme() string
    19  	GetPublicKey() string
    20  	GetNumRequired() int
    21  	GetSignerThresholdIDs() Stringers
    22  	GetSignerPublicKeys() Stringers
    23  }
    24  
    25  // Stringers wraps the methods for accessing string slice
    26  type Stringers interface {
    27  	Len() int                  // return the number of string slice
    28  	Get(i int) (string, error) // get string of given index
    29  }
    30  
    31  // stringSlice implements the Stringers interface
    32  type stringSlice []string
    33  
    34  func (ss stringSlice) Len() int {
    35  	return len(ss)
    36  }
    37  
    38  func (ss stringSlice) Get(i int) (string, error) {
    39  	if i < 0 || i >= len(ss) {
    40  		return "", errors.New("index out of bounds")
    41  	}
    42  	return ss[i], nil
    43  }
    44  
    45  //GetMultisigPayload given a multisig wallet as a string, makes a multisig wallet payload to register
    46  func GetMultisigPayload(mswstr string) (MultisigSCWallet, error) {
    47  	var msw msWallet
    48  	err := json.Unmarshal([]byte(mswstr), &msw)
    49  	if err != nil {
    50  		return nil, err
    51  	}
    52  
    53  	var signerThresholdIDs []string
    54  	var signerPublicKeys []string
    55  
    56  	for _, scheme := range msw.SignerKeys {
    57  		signerThresholdIDs = append(signerThresholdIDs, scheme.GetID())
    58  		signerPublicKeys = append(signerPublicKeys, scheme.GetPublicKey())
    59  	}
    60  
    61  	return &multisigSCWallet{
    62  		ClientID:        msw.GroupClientID,
    63  		SignatureScheme: msw.SignatureScheme,
    64  		PublicKey:       msw.GroupKey.GetPublicKey(),
    65  
    66  		SignerThresholdIDs: signerThresholdIDs,
    67  		SignerPublicKeys:   signerPublicKeys,
    68  
    69  		NumRequired: msw.T,
    70  	}, nil
    71  }
    72  
    73  type multisigSCWallet struct {
    74  	ClientID        string `json:"client_id"`
    75  	SignatureScheme string `json:"signature_scheme"`
    76  	PublicKey       string `json:"public_key"`
    77  
    78  	SignerThresholdIDs []string `json:"signer_threshold_ids"`
    79  	SignerPublicKeys   []string `json:"signer_public_keys"`
    80  
    81  	NumRequired int `json:"num_required"`
    82  }
    83  
    84  func (m *multisigSCWallet) GetClientID() string {
    85  	return m.ClientID
    86  }
    87  
    88  func (m *multisigSCWallet) GetSignatureScheme() string {
    89  	return m.SignatureScheme
    90  }
    91  
    92  func (m *multisigSCWallet) GetPublicKey() string {
    93  	return m.PublicKey
    94  }
    95  
    96  func (m *multisigSCWallet) GetSignerThresholdIDs() Stringers {
    97  	return stringSlice(m.SignerThresholdIDs)
    98  }
    99  
   100  func (m *multisigSCWallet) GetSignerPublicKeys() Stringers {
   101  	return stringSlice(m.SignerPublicKeys)
   102  }
   103  
   104  func (m *multisigSCWallet) GetNumRequired() int {
   105  	return m.NumRequired
   106  }
   107  
   108  type msWallet struct {
   109  	Id              int                         `json:"id"`
   110  	SignatureScheme string                      `json:"signature_scheme"`
   111  	GroupClientID   string                      `json:"group_client_id"`
   112  	GroupKey        zcncrypto.SignatureScheme   `json:"group_key"`
   113  	SignerClientIDs []string                    `json:"sig_client_ids"`
   114  	SignerKeys      []zcncrypto.SignatureScheme `json:"signer_keys"`
   115  	T               int                         `json:"threshold"`
   116  	N               int                         `json:"num_subkeys"`
   117  }
   118  
   119  func (msw *msWallet) UnmarshalJSON(data []byte) error {
   120  	m := &struct {
   121  		Id              int         `json:"id"`
   122  		SignatureScheme string      `json:"signature_scheme"`
   123  		GroupClientID   string      `json:"group_client_id"`
   124  		SignerClientIDs []string    `json:"sig_client_ids"`
   125  		T               int         `json:"threshold"`
   126  		N               int         `json:"num_subkeys"`
   127  		GroupKey        interface{} `json:"group_key"`
   128  		SignerKeys      interface{} `json:"signer_keys"`
   129  	}{}
   130  
   131  	if err := json.Unmarshal(data, &m); err != nil {
   132  		return err
   133  	}
   134  
   135  	msw.Id = m.Id
   136  	msw.SignatureScheme = m.SignatureScheme
   137  	msw.GroupClientID = m.GroupClientID
   138  	msw.SignerClientIDs = m.SignerClientIDs
   139  	msw.T = m.T
   140  	msw.N = m.N
   141  
   142  	if m.GroupKey != nil {
   143  		groupKeyBuf, err := json.Marshal(m.GroupKey)
   144  		if err != nil {
   145  			return err
   146  		}
   147  
   148  		ss := zcncrypto.NewSignatureScheme(m.SignatureScheme)
   149  
   150  		if err := json.Unmarshal(groupKeyBuf, &ss); err != nil {
   151  			return err
   152  		}
   153  
   154  		msw.GroupKey = ss
   155  	}
   156  
   157  	signerKeys, err := zcncrypto.UnmarshalSignatureSchemes(m.SignatureScheme, m.SignerKeys)
   158  	if err != nil {
   159  		return err
   160  	}
   161  	msw.SignerKeys = signerKeys
   162  
   163  	return nil
   164  }
   165  
   166  // Marshal returns json string
   167  func (msw *msWallet) Marshal() (string, error) {
   168  	msws, err := json.Marshal(msw)
   169  	if err != nil {
   170  		return "", errors.New("invalid wallet")
   171  	}
   172  	return string(msws), nil
   173  }
   174  
   175  type MSVote interface {
   176  	GetProposalID() string
   177  	GetSignature() string
   178  	GetTransferClientID() string
   179  	GetTransferToClientID() string
   180  	GetTransferAmount() string
   181  }
   182  
   183  type msVote struct {
   184  	ProposalID string `json:"proposal_id"`
   185  
   186  	// Client ID in transfer is that of the multi-sig wallet, not the signer.
   187  	Transfer msTransfer `json:"transfer"`
   188  
   189  	Signature string `json:"signature"`
   190  }
   191  
   192  func (m *msVote) GetProposalID() string {
   193  	return m.ProposalID
   194  }
   195  
   196  func (m *msVote) GetTransferClientID() string {
   197  	return m.Transfer.ClientID
   198  }
   199  
   200  func (m *msVote) GetTransferToClientID() string {
   201  	return m.Transfer.ToClientID
   202  }
   203  
   204  func (m *msVote) GetTransferAmount() string {
   205  	return strconv.FormatUint(m.Transfer.Amount, 10)
   206  }
   207  
   208  func (m *msVote) GetSignature() string {
   209  	return m.Signature
   210  }
   211  
   212  //msTransfer - a data structure to hold state transfer from one client to another
   213  type msTransfer struct {
   214  	ClientID   string `json:"from"`
   215  	ToClientID string `json:"to"`
   216  	Amount     uint64 `json:"amount"`
   217  }
   218  
   219  //GetMultisigVotePayload given a multisig vote as a string, makes a multisig vote payload to register
   220  func GetMultisigVotePayload(msvstr string) (MSVote, error) {
   221  	var msv msVote
   222  	err := json.Unmarshal([]byte(msvstr), &msv)
   223  	if err != nil {
   224  		return nil, err
   225  	}
   226  
   227  	return &msv, nil
   228  }
   229  
   230  // CreateMSVote create a vote for multisig
   231  func CreateMSVote(proposal, grpClientID, signerWalletstr, toClientID string, tokenStr string) (string, error) {
   232  	if proposal == "" || grpClientID == "" || toClientID == "" || signerWalletstr == "" {
   233  		return "", errors.New("proposal or groupClient or signer wallet or toClientID cannot be empty")
   234  	}
   235  
   236  	token, err := strconv.ParseUint(tokenStr, 10, 64)
   237  	if err != nil {
   238  		return "", err
   239  	}
   240  
   241  	if token < 1 {
   242  		return "", errors.New("token cannot be less than 1")
   243  	}
   244  
   245  	signerWallet, err := getWallet(signerWalletstr)
   246  	if err != nil {
   247  		return "", err
   248  	}
   249  
   250  	//Note: Is this honored by multisig sc?
   251  	transfer := msTransfer{
   252  		ClientID:   grpClientID,
   253  		ToClientID: toClientID,
   254  		Amount:     token,
   255  	}
   256  
   257  	buff, _ := json.Marshal(transfer)
   258  	hash := encryption.Hash(buff)
   259  
   260  	sigScheme := zcncrypto.NewSignatureScheme(_config.chain.SignatureScheme)
   261  	if err := sigScheme.SetPrivateKey(signerWallet.Keys[0].PrivateKey); err != nil {
   262  		return "", err
   263  	}
   264  
   265  	sig, err := sigScheme.Sign(hash)
   266  	if err != nil {
   267  		return "", err
   268  	}
   269  
   270  	vote := msVote{
   271  		Transfer:   transfer,
   272  		ProposalID: proposal,
   273  		Signature:  sig,
   274  	}
   275  
   276  	vbytes, err := json.Marshal(vote)
   277  	if err != nil {
   278  		fmt.Printf("error in marshalling vote %v", vote)
   279  		return "", err
   280  	}
   281  	return string(vbytes), nil
   282  }