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

     1  //go:build !mobile
     2  // +build !mobile
     3  
     4  package zcncore
     5  
     6  import (
     7  	"encoding/json"
     8  	"fmt"
     9  
    10  	"github.com/0chain/errors"
    11  	"github.com/0chain/gosdk/core/encryption"
    12  	"github.com/0chain/gosdk/core/zcncrypto"
    13  )
    14  
    15  //MSVote -- this should mimic the type Vote defined in MultiSig SC
    16  type MSVote struct {
    17  	ProposalID string `json:"proposal_id"`
    18  
    19  	// Client ID in transfer is that of the multi-sig wallet, not the signer.
    20  	Transfer MSTransfer `json:"transfer"`
    21  
    22  	Signature string `json:"signature"`
    23  }
    24  
    25  //MSTransfer - a data structure to hold state transfer from one client to another
    26  type MSTransfer struct {
    27  	ClientID   string `json:"from"`
    28  	ToClientID string `json:"to"`
    29  	Amount     uint64 `json:"amount"`
    30  }
    31  
    32  // MultisigSCWallet --this should mimic MultisigWallet definition in MultiSig SC
    33  type MultisigSCWallet struct {
    34  	ClientID        string `json:"client_id"`
    35  	SignatureScheme string `json:"signature_scheme"`
    36  	PublicKey       string `json:"public_key"`
    37  
    38  	SignerThresholdIDs []string `json:"signer_threshold_ids"`
    39  	SignerPublicKeys   []string `json:"signer_public_keys"`
    40  
    41  	NumRequired int `json:"num_required"`
    42  }
    43  
    44  // MSWallet Client data necessary for a multi-sig wallet.
    45  type MSWallet struct {
    46  	Id              int                         `json:"id"`
    47  	SignatureScheme string                      `json:"signature_scheme"`
    48  	GroupClientID   string                      `json:"group_client_id"`
    49  	GroupKey        zcncrypto.SignatureScheme   `json:"group_key"`
    50  	SignerClientIDs []string                    `json:"sig_client_ids"`
    51  	SignerKeys      []zcncrypto.SignatureScheme `json:"signer_keys"`
    52  	T               int                         `json:"threshold"`
    53  	N               int                         `json:"num_subkeys"`
    54  }
    55  
    56  func (msw *MSWallet) UnmarshalJSON(data []byte) error {
    57  	m := &struct {
    58  		Id              int         `json:"id"`
    59  		SignatureScheme string      `json:"signature_scheme"`
    60  		GroupClientID   string      `json:"group_client_id"`
    61  		SignerClientIDs []string    `json:"sig_client_ids"`
    62  		T               int         `json:"threshold"`
    63  		N               int         `json:"num_subkeys"`
    64  		GroupKey        interface{} `json:"group_key"`
    65  		SignerKeys      interface{} `json:"signer_keys"`
    66  	}{}
    67  
    68  	if err := json.Unmarshal(data, &m); err != nil {
    69  		return err
    70  	}
    71  
    72  	msw.Id = m.Id
    73  	msw.SignatureScheme = m.SignatureScheme
    74  	msw.GroupClientID = m.GroupClientID
    75  	msw.SignerClientIDs = m.SignerClientIDs
    76  	msw.T = m.T
    77  	msw.N = m.N
    78  
    79  	if m.GroupKey != nil {
    80  		groupKeyBuf, err := json.Marshal(m.GroupKey)
    81  		if err != nil {
    82  			return err
    83  		}
    84  
    85  		ss := zcncrypto.NewSignatureScheme(m.SignatureScheme)
    86  
    87  		if err := json.Unmarshal(groupKeyBuf, &ss); err != nil {
    88  			return err
    89  		}
    90  
    91  		msw.GroupKey = ss
    92  	}
    93  
    94  	signerKeys, err := zcncrypto.UnmarshalSignatureSchemes(m.SignatureScheme, m.SignerKeys)
    95  	if err != nil {
    96  		return err
    97  	}
    98  	msw.SignerKeys = signerKeys
    99  
   100  	return nil
   101  }
   102  
   103  // Marshal returns json string
   104  func (msw *MSWallet) Marshal() (string, error) {
   105  	msws, err := json.Marshal(msw)
   106  	if err != nil {
   107  		return "", errors.New("", "Invalid Wallet")
   108  	}
   109  	return string(msws), nil
   110  }
   111  
   112  //GetMultisigPayload given a multisig wallet as a string, makes a multisig wallet payload to register
   113  func GetMultisigPayload(mswstr string) (interface{}, error) {
   114  	var msw MSWallet
   115  	err := json.Unmarshal([]byte(mswstr), &msw)
   116  
   117  	if err != nil {
   118  		fmt.Printf("Error while creating multisig wallet from input:\n%v", mswstr)
   119  		return "", err
   120  	}
   121  	var signerThresholdIDs []string
   122  	var signerPublicKeys []string
   123  
   124  	for _, scheme := range msw.SignerKeys {
   125  		signerThresholdIDs = append(signerThresholdIDs, scheme.GetID())
   126  		signerPublicKeys = append(signerPublicKeys, scheme.GetPublicKey())
   127  	}
   128  
   129  	msscw := MultisigSCWallet{
   130  		ClientID:        msw.GroupClientID,
   131  		SignatureScheme: msw.SignatureScheme,
   132  		PublicKey:       msw.GroupKey.GetPublicKey(),
   133  
   134  		SignerThresholdIDs: signerThresholdIDs,
   135  		SignerPublicKeys:   signerPublicKeys,
   136  
   137  		NumRequired: msw.T,
   138  	}
   139  
   140  	return msscw, nil
   141  }
   142  
   143  //GetMultisigVotePayload given a multisig vote as a string, makes a multisig vote payload to register
   144  func GetMultisigVotePayload(msvstr string) (interface{}, error) {
   145  	var msv MSVote
   146  	err := json.Unmarshal([]byte(msvstr), &msv)
   147  
   148  	if err != nil {
   149  		fmt.Printf("Error while creating multisig wallet from input:\n%v", msvstr)
   150  		return nil, err
   151  	}
   152  
   153  	//Marshalling and unmarshalling validates the string. Do any additional veirfication here.
   154  
   155  	return msv, nil
   156  
   157  }
   158  
   159  // CreateMSVote create a vote for multisig
   160  func CreateMSVote(proposal, grpClientID, signerWalletstr, toClientID string, token uint64) (string, error) {
   161  	if proposal == "" || grpClientID == "" || toClientID == "" || signerWalletstr == "" {
   162  		return "", errors.New("", "proposal or groupClient or signer wallet or toClientID cannot be empty")
   163  	}
   164  
   165  	if token < 1 {
   166  		return "", errors.New("", "Token cannot be less than 1")
   167  	}
   168  
   169  	signerWallet, err := getWallet(signerWalletstr)
   170  	if err != nil {
   171  		fmt.Printf("Error while parsing the signer wallet. %v", err)
   172  		return "", err
   173  	}
   174  
   175  	//Note: Is this honored by multisig sc?
   176  	transfer := MSTransfer{
   177  		ClientID:   grpClientID,
   178  		ToClientID: toClientID,
   179  		Amount:     token,
   180  	}
   181  
   182  	buff, _ := json.Marshal(transfer)
   183  	hash := encryption.Hash(buff)
   184  
   185  	sigScheme := zcncrypto.NewSignatureScheme(_config.chain.SignatureScheme)
   186  	if err := sigScheme.SetPrivateKey(signerWallet.Keys[0].PrivateKey); err != nil {
   187  		return "", err
   188  	}
   189  
   190  	sig, err := sigScheme.Sign(hash)
   191  	if err != nil {
   192  		return "", err
   193  	}
   194  
   195  	vote := MSVote{
   196  		Transfer:   transfer,
   197  		ProposalID: proposal,
   198  		Signature:  sig,
   199  	}
   200  
   201  	vbytes, err := json.Marshal(vote)
   202  	if err != nil {
   203  		fmt.Printf("error in marshalling vote %v", vote)
   204  		return "", err
   205  	}
   206  	return string(vbytes), nil
   207  }