1// SPDX-License-Identifier: ISC 2// Copyright (c) 2014-2020 Bitmark Inc. 3// Use of this source code is governed by an ISC 4// license that can be found in the LICENSE file. 5 6package rpccalls 7 8import ( 9 "golang.org/x/crypto/ed25519" 10 11 "github.com/bitmark-inc/bitmarkd/command/bitmark-cli/configuration" 12 "github.com/bitmark-inc/bitmarkd/fault" 13 "github.com/bitmark-inc/bitmarkd/merkle" 14 "github.com/bitmark-inc/bitmarkd/pay" 15 "github.com/bitmark-inc/bitmarkd/rpc/share" 16 "github.com/bitmark-inc/bitmarkd/transactionrecord" 17) 18 19// ShareData - data for a share request 20type ShareData struct { 21 Owner *configuration.Private 22 NewOwner *configuration.Private 23 TxId string 24 Quantity uint64 25} 26 27// ShareReply - JSON data to output after transfer completes 28type ShareReply struct { 29 TxId merkle.Digest `json:"txId"` 30 ShareId merkle.Digest `json:"shareId"` 31 PayId pay.PayId `json:"payId"` 32 Payments map[string]transactionrecord.PaymentAlternative `json:"payments"` 33 Commands map[string]string `json:"commands,omitempty"` 34} 35 36// Share - perform a share request 37func (client *Client) Share(shareConfig *ShareData) (*ShareReply, error) { 38 39 var link merkle.Digest 40 err := link.UnmarshalText([]byte(shareConfig.TxId)) 41 if nil != err { 42 return nil, err 43 } 44 45 sh, err := makeShare(client.testnet, link, shareConfig.Quantity, shareConfig.Owner) 46 if nil != err { 47 return nil, err 48 } 49 if nil == sh { 50 return nil, fault.MakeShareFailed 51 } 52 53 client.printJson("Share Request", sh) 54 55 var reply share.CreateReply 56 err = client.client.Call("Share.Create", sh, &reply) 57 if err != nil { 58 return nil, err 59 } 60 61 tpid, err := reply.PayId.MarshalText() 62 if nil != err { 63 return nil, err 64 } 65 66 commands := make(map[string]string) 67 for _, payment := range reply.Payments { 68 currency := payment[0].Currency 69 commands[currency.String()] = paymentCommand(client.testnet, currency, string(tpid), payment) 70 } 71 72 client.printJson("Share Reply", reply) 73 74 // make response 75 response := ShareReply{ 76 TxId: reply.TxId, 77 ShareId: reply.ShareId, 78 PayId: reply.PayId, 79 Payments: reply.Payments, 80 Commands: commands, 81 } 82 83 return &response, nil 84} 85 86func makeShare(testnet bool, link merkle.Digest, quantity uint64, owner *configuration.Private) (*transactionrecord.BitmarkShare, error) { 87 88 r := transactionrecord.BitmarkShare{ 89 Link: link, 90 Quantity: quantity, 91 Signature: nil, 92 } 93 94 ownerAccount := owner.PrivateKey.Account() 95 96 // pack without signature 97 packed, err := r.Pack(ownerAccount) 98 if nil == err { 99 return nil, fault.MakeShareFailed 100 } else if fault.InvalidSignature != err { 101 return nil, err 102 } 103 104 // attach signature 105 signature := ed25519.Sign(owner.PrivateKey.PrivateKeyBytes(), packed) 106 r.Signature = signature[:] 107 108 // check that signature is correct by packing again 109 _, err = r.Pack(ownerAccount) 110 if nil != err { 111 return nil, err 112 } 113 return &r, nil 114} 115