OSDN Git Service

Voter reward (#344)
[bytom/vapor.git] / toolbar / apinode / transaction.go
diff --git a/toolbar/apinode/transaction.go b/toolbar/apinode/transaction.go
new file mode 100644 (file)
index 0000000..82ff3c9
--- /dev/null
@@ -0,0 +1,138 @@
+package apinode
+
+import (
+       "encoding/json"
+
+       "github.com/vapor/blockchain/txbuilder"
+       "github.com/vapor/consensus"
+       "github.com/vapor/errors"
+       "github.com/vapor/protocol/bc"
+       "github.com/vapor/protocol/bc/types"
+)
+
+type SpendAccountAction struct {
+       AccountID string `json:"account_id"`
+       *bc.AssetAmount
+}
+
+func (s *SpendAccountAction) MarshalJSON() ([]byte, error) {
+       return json.Marshal(&struct {
+               Type      string `json:"type"`
+               AccountID string `json:"account_id"`
+               *bc.AssetAmount
+       }{
+               Type:        "spend_account",
+               AccountID:   s.AccountID,
+               AssetAmount: s.AssetAmount,
+       })
+}
+
+type ControlAddressAction struct {
+       Address string `json:"address"`
+       *bc.AssetAmount
+}
+
+func (c *ControlAddressAction) MarshalJSON() ([]byte, error) {
+       return json.Marshal(&struct {
+               Type    string `json:"type"`
+               Address string `json:"address"`
+               *bc.AssetAmount
+       }{
+               Type:        "control_address",
+               Address:     c.Address,
+               AssetAmount: c.AssetAmount,
+       })
+}
+
+func (n *Node) BatchSendBTM(accountID, password string, outputs map[string]uint64) error {
+       totalBTM := uint64(10000000)
+       actions := []interface{}{}
+       for address, amount := range outputs {
+               actions = append(actions, &ControlAddressAction{
+                       Address:     address,
+                       AssetAmount: &bc.AssetAmount{AssetId: consensus.BTMAssetID, Amount: amount},
+               })
+               totalBTM += amount
+       }
+
+       actions = append(actions, &SpendAccountAction{
+               AccountID:   accountID,
+               AssetAmount: &bc.AssetAmount{AssetId: consensus.BTMAssetID, Amount: totalBTM},
+       })
+
+       tpl, err := n.buildTx(actions)
+       if err != nil {
+               return err
+       }
+
+       tpl, err = n.signTx(tpl, password)
+       if err != nil {
+               return err
+       }
+
+       _, err = n.SubmitTx(tpl.Transaction)
+       return err
+}
+
+type buildTxReq struct {
+       Actions []interface{} `json:"actions"`
+}
+
+func (n *Node) buildTx(actions []interface{}) (*txbuilder.Template, error) {
+       url := "/build-transaction"
+       payload, err := json.Marshal(&buildTxReq{Actions: actions})
+       if err != nil {
+               return nil, errors.Wrap(err, "Marshal spend request")
+       }
+
+       result := &txbuilder.Template{}
+       return result, n.request(url, payload, result)
+}
+
+type signTxReq struct {
+       Tx       *txbuilder.Template `json:"transaction"`
+       Password string              `json:"password"`
+}
+
+type signTxResp struct {
+       Tx           *txbuilder.Template `json:"transaction"`
+       SignComplete bool                `json:"sign_complete"`
+}
+
+func (n *Node) signTx(tpl *txbuilder.Template, password string) (*txbuilder.Template, error) {
+       url := "/sign-transaction"
+       payload, err := json.Marshal(&signTxReq{Tx: tpl, Password: password})
+       if err != nil {
+               return nil, errors.Wrap(err, "json marshal")
+       }
+
+       resp := &signTxResp{}
+       if err := n.request(url, payload, resp); err != nil {
+               return nil, err
+       }
+
+       if !resp.SignComplete {
+               return nil, errors.New("sign fail")
+       }
+
+       return resp.Tx, nil
+}
+
+type submitTxReq struct {
+       Tx *types.Tx `json:"raw_transaction"`
+}
+
+type submitTxResp struct {
+       TxID string `json:"tx_id"`
+}
+
+func (n *Node) SubmitTx(tx *types.Tx) (string, error) {
+       url := "/submit-transaction"
+       payload, err := json.Marshal(submitTxReq{Tx: tx})
+       if err != nil {
+               return "", errors.Wrap(err, "json marshal")
+       }
+
+       res := &submitTxResp{}
+       return res.TxID, n.request(url, payload, res)
+}