OSDN Git Service

Merge branch 'master' into multi-sign
[bytom/bytom-electron.git] / src / features / transactions / actions.js
1 import uuid from 'uuid'
2 import { chainClient } from 'utility/environment'
3 import { parseNonblankJSON } from 'utility/string'
4 import { push } from 'react-router-redux'
5 import { baseCreateActions, baseListActions } from 'features/shared/actions'
6
7 const type = 'transaction'
8
9 const list = baseListActions(type, {
10   defaultKey: 'id'
11 })
12 const form = baseCreateActions(type)
13
14 function preprocessTransaction(formParams) {
15   const copy = JSON.parse(JSON.stringify(formParams))
16   const builder = {
17     baseTransaction: copy.baseTransaction,
18     actions: copy.actions,
19   }
20
21   const normalT = formParams.normalTransaction
22   if( builder.actions.length == 0){
23     builder.actions.push({accountAlias: normalT.accountAlias, accountId: normalT.accountId, assetAlias: 'btm', amount: Number(normalT.gas.price), type: 'spend_account'})
24     builder.actions.push({accountAlias: normalT.accountAlias, accountId: normalT.accountId, assetAlias: normalT.assetAlias, assetId: normalT.assetId, amount: normalT.amount, type: 'spend_account'})
25     builder.actions.push({address: normalT.address, assetAlias: normalT.assetAlias, assetId: normalT.assetId, amount: normalT.amount, type: 'control_address'})
26   }
27
28   if (builder.baseTransaction == '') {
29     delete builder.baseTransaction
30   }
31
32   if (formParams.submitAction == 'generate') {
33     builder.ttl = '1h' // 1 hour
34   }
35
36   for (let i in builder.actions) {
37     let a = builder.actions[i]
38
39     const intFields = ['amount', 'position']
40     intFields.forEach(key => {
41       const value = a[key]
42       if (value) {
43         if ((parseInt(value)+'') == value) {
44           a[key] = parseInt(value)
45         } else {
46           throw new Error(`Action ${parseInt(i)+1} ${key} must be an integer.`)
47         }
48       }
49     })
50
51     try {
52       a.referenceData = parseNonblankJSON(a.referenceData)
53     } catch (err) {
54       throw new Error(`Action ${parseInt(i)+1} reference data should be valid JSON, or blank.`)
55     }
56
57     try {
58       a.receiver = parseNonblankJSON(a.receiver)
59     } catch (err) {
60       throw new Error(`Action ${parseInt(i)+1} receiver should be valid JSON.`)
61     }
62   }
63
64   return builder
65 }
66
67 form.submitForm = (formParams) => function(dispatch) {
68   const buildPromise = chainClient().transactions.build(builder => {
69     const processed = preprocessTransaction(formParams)
70
71     builder.actions = processed.actions.map(action => {
72       let result = {
73         address: action.address,
74         amount: action.amount,
75         account_id: action.accountId,
76         account_alias: action.accountAlias,
77         asset_id: action.assetId,
78         asset_alias: action.assetAlias,
79         type: action.type,
80       }
81       if (action.receiver) {
82         result.receiver = {
83           control_program: action.receiver.controlProgram,
84           expires_at: action.receiver.expiresAt
85         }
86       }
87       return result
88     })
89     if (processed.baseTransaction) {
90       builder.baseTransaction = processed.baseTransaction
91     }
92   })
93
94   if (formParams.submitAction == 'submit') {
95     return buildPromise
96       .then((resp) => {
97         if (resp.status === 'fail') {
98           throw new Error(resp.msg)
99         }
100
101         const tpl = resp.data
102         const password = (tpl.signing_instructions || []).map(() => '123456')
103         const client = chainClient()
104         const body = Object.assign({}, {password, 'transaction': tpl})
105         return client.connection.request('/sign-submit-transaction', body, true)
106       }).then(resp => {
107         if (resp.status === 'fail') {
108           throw new Error(resp.msg)
109         }
110
111         dispatch(form.created())
112         dispatch(push({
113           pathname: '/transactions'
114         }))
115       })
116   }
117
118   // submitAction == 'generate'
119   return buildPromise.then(resp => {
120     if (resp.status === 'fail') {
121       throw new Error(resp.msg)
122     }
123
124     const tpl = resp.data
125     const password = (tpl.signing_instructions || []).map(() => '123456')
126     const client = chainClient()
127     const body = Object.assign({}, {password, 'transaction': tpl})
128     return client.connection.request('/sign-transaction', body, true)
129   }).then(resp => {
130     if (resp.status === 'fail') {
131       throw new Error(resp.msg)
132     }
133     const id = uuid.v4()
134     dispatch({
135       type: 'GENERATED_TX_HEX',
136       generated: {
137         id: id,
138         hex: resp.data.raw_transaction,
139       },
140     })
141     dispatch(push(`/transactions/generated/${id}`))
142   })
143 }
144
145 export default {
146   ...list,
147   ...form,
148 }