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 }