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