OSDN Git Service

4e9c24222a741c622c3849c267fbc2cf1e31005c
[bytom/vapor.git] / toolbar / apinode / transaction.go
1 package apinode
2
3 import (
4         "encoding/hex"
5         "encoding/json"
6
7         "github.com/vapor/blockchain/txbuilder"
8         "github.com/vapor/consensus"
9         "github.com/vapor/errors"
10         "github.com/vapor/protocol/bc"
11         "github.com/vapor/protocol/bc/types"
12 )
13
14 type SpendAccountAction struct {
15         AccountID string `json:"account_id"`
16         *bc.AssetAmount
17 }
18
19 func (s *SpendAccountAction) MarshalJSON() ([]byte, error) {
20         return json.Marshal(&struct {
21                 Type      string `json:"type"`
22                 AccountID string `json:"account_id"`
23                 *bc.AssetAmount
24         }{
25                 Type:        "spend_account",
26                 AccountID:   s.AccountID,
27                 AssetAmount: s.AssetAmount,
28         })
29 }
30
31 type ControlAddressAction struct {
32         Address string `json:"address"`
33         *bc.AssetAmount
34 }
35
36 func (c *ControlAddressAction) MarshalJSON() ([]byte, error) {
37         return json.Marshal(&struct {
38                 Type    string `json:"type"`
39                 Address string `json:"address"`
40                 *bc.AssetAmount
41         }{
42                 Type:        "control_address",
43                 Address:     c.Address,
44                 AssetAmount: c.AssetAmount,
45         })
46 }
47
48 type RetireAction struct {
49         *bc.AssetAmount
50         Arbitrary []byte
51 }
52
53 func (r *RetireAction) MarshalJSON() ([]byte, error) {
54         return json.Marshal(&struct {
55                 Type      string `json:"type"`
56                 Arbitrary string `json:"arbitrary"`
57                 *bc.AssetAmount
58         }{
59                 Type:        "retire",
60                 Arbitrary:   hex.EncodeToString(r.Arbitrary),
61                 AssetAmount: r.AssetAmount,
62         })
63 }
64
65 func (n *Node) BatchSendBTM(accountID, password string, outputs map[string]uint64, memo []byte) (string, error) {
66         totalBTM := uint64(1000000)
67         actions := []interface{}{}
68         if len(memo) > 0 {
69                 actions = append(actions, &RetireAction{
70                         Arbitrary:   memo,
71                         AssetAmount: &bc.AssetAmount{AssetId: consensus.BTMAssetID, Amount: 1},
72                 })
73         }
74
75         for address, amount := range outputs {
76                 actions = append(actions, &ControlAddressAction{
77                         Address:     address,
78                         AssetAmount: &bc.AssetAmount{AssetId: consensus.BTMAssetID, Amount: amount},
79                 })
80                 totalBTM += amount
81         }
82
83         actions = append(actions, &SpendAccountAction{
84                 AccountID:   accountID,
85                 AssetAmount: &bc.AssetAmount{AssetId: consensus.BTMAssetID, Amount: totalBTM},
86         })
87
88         tpl, err := n.buildTx(actions)
89         if err != nil {
90                 return "", err
91         }
92
93         tpl, err = n.signTx(tpl, password)
94         if err != nil {
95                 return "", err
96         }
97
98         return n.SubmitTx(tpl.Transaction)
99 }
100
101 type buildTxReq struct {
102         Actions []interface{} `json:"actions"`
103 }
104
105 func (n *Node) buildTx(actions []interface{}) (*txbuilder.Template, error) {
106         url := "/build-transaction"
107         payload, err := json.Marshal(&buildTxReq{Actions: actions})
108         if err != nil {
109                 return nil, errors.Wrap(err, "Marshal spend request")
110         }
111
112         result := &txbuilder.Template{}
113         return result, n.request(url, payload, result)
114 }
115
116 func (n *Node) BuildChainTxs(actions []interface{}) ([]*txbuilder.Template, error) {
117         url := "/build-chain-transactions"
118
119         payload, err := json.Marshal(&buildTxReq{Actions: actions})
120         if err != nil {
121                 return nil, errors.Wrap(err, "Marshal spend request")
122         }
123
124         result := []*txbuilder.Template{}
125         return result, n.request(url, payload, &result)
126 }
127
128 type signTxReq struct {
129         Tx       *txbuilder.Template `json:"transaction"`
130         Password string              `json:"password"`
131 }
132
133 type signTxResp struct {
134         Tx           *txbuilder.Template `json:"transaction"`
135         SignComplete bool                `json:"sign_complete"`
136 }
137
138 func (n *Node) signTx(tpl *txbuilder.Template, password string) (*txbuilder.Template, error) {
139         url := "/sign-transaction"
140         payload, err := json.Marshal(&signTxReq{Tx: tpl, Password: password})
141         if err != nil {
142                 return nil, errors.Wrap(err, "json marshal")
143         }
144
145         resp := &signTxResp{}
146         if err := n.request(url, payload, resp); err != nil {
147                 return nil, err
148         }
149
150         if !resp.SignComplete {
151                 return nil, errors.New("sign fail")
152         }
153
154         return resp.Tx, nil
155 }
156
157 type signTxsReq struct {
158         Txs      []*txbuilder.Template `json:"transactions"`
159         Password string                `json:"password"`
160 }
161
162 type signTxsResp struct {
163         Txs          []*txbuilder.Template `json:"transaction"`
164         SignComplete bool                  `json:"sign_complete"`
165 }
166
167 func (n *Node) SignTxs(tpls []*txbuilder.Template, password string) ([]*txbuilder.Template, error) {
168         url := "/sign-transactions"
169         payload, err := json.Marshal(&signTxsReq{Txs: tpls, Password: password})
170         if err != nil {
171                 return nil, errors.Wrap(err, "json marshal")
172         }
173
174         resp := &signTxsResp{}
175         if err := n.request(url, payload, resp); err != nil {
176                 return nil, err
177         }
178
179         if !resp.SignComplete {
180                 return nil, errors.New("sign fail")
181         }
182
183         return resp.Txs, nil
184 }
185
186 type submitTxReq struct {
187         Tx *types.Tx `json:"raw_transaction"`
188 }
189
190 type submitTxResp struct {
191         TxID string `json:"tx_id"`
192 }
193
194 func (n *Node) SubmitTx(tx *types.Tx) (string, error) {
195         url := "/submit-transaction"
196         payload, err := json.Marshal(submitTxReq{Tx: tx})
197         if err != nil {
198                 return "", errors.Wrap(err, "json marshal")
199         }
200
201         res := &submitTxResp{}
202         return res.TxID, n.request(url, payload, res)
203 }
204
205 type submitTxsReq struct {
206         Txs []*types.Tx `json:"raw_transactions"`
207 }
208
209 type submitTxsResp struct {
210         TxsID []string `json:"tx_id"`
211 }
212
213 func (n *Node) SubmitTxs(txs []*types.Tx) ([]string, error) {
214         url := "/submit-transactions"
215         payload, err := json.Marshal(submitTxsReq{Txs: txs})
216         if err != nil {
217                 return []string{}, errors.Wrap(err, "json marshal")
218         }
219
220         res := &submitTxsResp{}
221         return res.TxsID, n.request(url, payload, res)
222 }