OSDN Git Service

Reward util (#342)
[bytom/vapor.git] / toolbar / api_node / transaction.go
1 package apinode
2
3 import (
4         "encoding/json"
5
6         "github.com/vapor/blockchain/txbuilder"
7         "github.com/vapor/consensus"
8         "github.com/vapor/errors"
9         "github.com/vapor/protocol/bc"
10         "github.com/vapor/protocol/bc/types"
11 )
12
13 type SpendAccountAction struct {
14         AccountID string `json:"account_id"`
15         *bc.AssetAmount
16 }
17
18 func (s *SpendAccountAction) MarshalJSON() ([]byte, error) {
19         return json.Marshal(&struct {
20                 Type      string `json:"type"`
21                 AccountID string `json:"account_id"`
22                 *bc.AssetAmount
23         }{
24                 Type:        "spend_account",
25                 AccountID:   s.AccountID,
26                 AssetAmount: s.AssetAmount,
27         })
28 }
29
30 type ControlAddressAction struct {
31         Address string `json:"address"`
32         *bc.AssetAmount
33 }
34
35 func (c *ControlAddressAction) MarshalJSON() ([]byte, error) {
36         return json.Marshal(&struct {
37                 Type    string `json:"type"`
38                 Address string `json:"address"`
39                 *bc.AssetAmount
40         }{
41                 Type:        "control_address",
42                 Address:     c.Address,
43                 AssetAmount: c.AssetAmount,
44         })
45 }
46
47 func (n *Node) BatchSendBTM(accountID, password string, outputs map[string]uint64) error {
48         totalBTM := uint64(10000000)
49         actions := []interface{}{}
50         for address, amount := range outputs {
51                 actions = append(actions, &ControlAddressAction{
52                         Address:     address,
53                         AssetAmount: &bc.AssetAmount{AssetId: consensus.BTMAssetID, Amount: amount},
54                 })
55                 totalBTM += amount
56         }
57
58         actions = append(actions, &SpendAccountAction{
59                 AccountID:   accountID,
60                 AssetAmount: &bc.AssetAmount{AssetId: consensus.BTMAssetID, Amount: totalBTM},
61         })
62
63         tpl, err := n.buildTx(actions)
64         if err != nil {
65                 return err
66         }
67
68         tpl, err = n.signTx(tpl, password)
69         if err != nil {
70                 return err
71         }
72
73         _, err = n.SubmitTx(tpl.Transaction)
74         return err
75 }
76
77 type buildTxReq struct {
78         Actions []interface{} `json:"actions"`
79 }
80
81 func (n *Node) buildTx(actions []interface{}) (*txbuilder.Template, error) {
82         url := "/build-transaction"
83         payload, err := json.Marshal(&buildTxReq{Actions: actions})
84         if err != nil {
85                 return nil, errors.Wrap(err, "Marshal spend request")
86         }
87
88         result := &txbuilder.Template{}
89         return result, n.request(url, payload, result)
90 }
91
92 type signTxReq struct {
93         Tx       *txbuilder.Template `json:"transaction"`
94         Password string              `json:"password"`
95 }
96
97 type signTxResp struct {
98         Tx           *txbuilder.Template `json:"transaction"`
99         SignComplete bool                `json:"sign_complete"`
100 }
101
102 func (n *Node) signTx(tpl *txbuilder.Template, password string) (*txbuilder.Template, error) {
103         url := "/sign-transaction"
104         payload, err := json.Marshal(&signTxReq{Tx: tpl, Password: password})
105         if err != nil {
106                 return nil, errors.Wrap(err, "json marshal")
107         }
108
109         resp := &signTxResp{}
110         if err := n.request(url, payload, resp); err != nil {
111                 return nil, err
112         }
113
114         if !resp.SignComplete {
115                 return nil, errors.New("sign fail")
116         }
117
118         return resp.Tx, nil
119 }
120
121 type submitTxReq struct {
122         Tx *types.Tx `json:"raw_transaction"`
123 }
124
125 type submitTxResp struct {
126         TxID string `json:"tx_id"`
127 }
128
129 func (n *Node) SubmitTx(tx *types.Tx) (string, error) {
130         url := "/submit-transaction"
131         payload, err := json.Marshal(submitTxReq{Tx: tx})
132         if err != nil {
133                 return "", errors.Wrap(err, "json marshal")
134         }
135
136         res := &submitTxResp{}
137         return res.TxID, n.request(url, payload, res)
138 }