OSDN Git Service

add the issue asset transactions page.
[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 import { normalTxActionBuilder, issueAssetTxActionBuilder } from './transactions'
7
8 const type = 'transaction'
9
10 const list = baseListActions(type, {
11   defaultKey: 'id'
12 })
13 const form = baseCreateActions(type)
14
15 function preprocessTransaction(formParams) {
16   const copy = JSON.parse(JSON.stringify(formParams))
17   const builder = {
18     baseTransaction: copy.baseTransaction,
19     actions: copy.actions || [],
20   }
21
22   if (formParams.form === 'normalTx') {
23     const gasPrice = formParams.state.estimateGas * Number(formParams.gasLevel)
24     builder.actions = normalTxActionBuilder(formParams,  Number(gasPrice), 'amount')
25   }
26
27   if (formParams.form === 'issueAssetTx') {
28     builder.actions = issueAssetTxActionBuilder(formParams,  'amount')
29   }
30
31
32   if (builder.baseTransaction == '') {
33     delete builder.baseTransaction
34   }
35
36   if (formParams.submitAction == 'generate') {
37     builder.ttl = '1h' // 1 hour
38   }
39
40   for (let i in builder.actions) {
41     let a = builder.actions[i]
42
43     const intFields = ['amount', 'position']
44     intFields.forEach(key => {
45       const value = a[key]
46       if (value) {
47         if ((parseInt(value) + '') == value) {
48           a[key] = parseInt(value)
49         } else {
50           throw new Error(`Action ${parseInt(i) + 1} ${key} must be an integer.`)
51         }
52       }
53     })
54
55     try {
56       a.referenceData = parseNonblankJSON(a.referenceData)
57     } catch (err) {
58       throw new Error(`Action ${parseInt(i) + 1} reference data should be valid JSON, or blank.`)
59     }
60
61     try {
62       a.receiver = parseNonblankJSON(a.receiver)
63     } catch (err) {
64       throw new Error(`Action ${parseInt(i) + 1} receiver should be valid JSON.`)
65     }
66   }
67
68   return builder
69 }
70
71 form.submitForm = (formParams) => function (dispatch) {
72   const client = chainClient()
73
74   const builderFunction = ( builder ) => {
75     const processed = preprocessTransaction(formParams)
76
77     builder.actions = processed.actions
78     if (processed.baseTransaction) {
79       builder.baseTransaction = processed.baseTransaction
80     }
81   }
82
83   const submitSucceeded = () => {
84     dispatch(form.created())
85     dispatch(push({
86       pathname: '/transactions',
87       state: {
88         preserveFlash: true
89       }
90     }))
91   }
92
93   // normal transactions
94   if( formParams.form === 'normalTx'){
95
96     const accountId = formParams.accountId
97     const accountAlias = formParams.accountAlias
98     const accountInfo = Object.assign({},  accountAlias!== ''? {alias: accountAlias}: {id: accountId})
99
100     return client.accounts.query(accountInfo)
101       .then( resp => {
102         if(resp.data[0].xpubs.length > 1){
103           throw {code: 'F_BTM003'}
104         }
105         const body = Object.assign({}, {xpub: resp.data[0].xpubs[0], password: formParams.password})
106         return client.mockHsm.keys.checkPassword(body)
107       })
108       .then( result => {
109         if(!result.data.checkResult){
110           throw new Error('PasswordWrong')
111         }
112         return client.transactions.build(builderFunction)
113       })
114       .then( tpl => {
115         const body = Object.assign({}, {password: formParams.password, transaction: tpl.data})
116         return client.transactions.sign(body)
117       })
118       .then(signed => {
119         if(!signed.data.signComplete){
120           throw {code: 'F_BTM100'}
121         }
122         return client.transactions.submit(signed.data.transaction.rawTransaction)
123       })
124       .then(submitSucceeded)
125   }
126
127   //advanced transactions
128   else if( formParams.form === 'advancedTx' ){
129     const buildPromise = (formParams.state.showAdvanced && formParams.signTransaction) ? null :
130       client.transactions.build(builderFunction)
131
132     if (formParams.submitAction == 'submit') {
133       const signAndSubmitTransaction = (transaction) => {
134         const body = Object.assign({}, {password: formParams.password, transaction: transaction})
135         return client.transactions.sign(body)
136           .then( signed => client.transactions.submit(signed.data.transaction.rawTransaction) )
137           .then(submitSucceeded)
138       }
139
140       if( formParams.state.showAdvanced
141         && formParams.signTransaction ){
142         const transaction = JSON.parse(formParams.signTransaction)
143         return signAndSubmitTransaction(transaction)
144       }
145
146       return buildPromise
147         .then(tpl => signAndSubmitTransaction(tpl.data))
148     }
149
150     // submitAction == 'generate'
151     const signAndSubmitGeneratedTransaction = (transaction) => {
152       const body = Object.assign({}, {password: formParams.password, transaction: transaction})
153       return client.transactions.sign(body)
154         .then(resp => {
155           const id = uuid.v4()
156           dispatch({
157             type: 'GENERATED_TX_HEX',
158             generated: {
159               id: id,
160               hex: JSON.stringify(resp.data.transaction),
161             },
162           })
163           dispatch(push(`/transactions/generated/${id}`))
164         })
165     }
166
167     if (formParams.state.showAdvanced
168       && formParams.signTransaction) {
169       const transaction = JSON.parse(formParams.signTransaction)
170       return signAndSubmitGeneratedTransaction(transaction)
171     }
172
173     return buildPromise
174       .then(resp => signAndSubmitGeneratedTransaction(resp.data))
175   }
176
177   //issue Asset transactions
178   else if( formParams.form === 'issueAssetTx'){
179     //submit action
180     const signAndSubmitTransaction = (transaction) => {
181       const body = Object.assign({}, {password: formParams.password, transaction: transaction})
182       return client.transactions.sign(body)
183         .then( signed =>{
184           if(!signed.data.signComplete){
185             const id = uuid.v4()
186             dispatch({
187               type: 'GENERATED_TX_HEX',
188               generated: {
189                 id: id,
190                 hex: JSON.stringify(signed.data.transaction),
191               },
192             })
193             dispatch(push(`/transactions/generated/${id}`))
194
195           }else{
196             return client.transactions.submit(signed.data.transaction.rawTransaction)
197               .then(submitSucceeded)
198           }
199         })
200     }
201
202     if (formParams.submitAction == 'submit') {
203       return client.transactions.build(builderFunction)
204         .then(tpl => signAndSubmitTransaction(tpl.data))
205     }
206
207     if( formParams.submitAction == 'sign' ){
208       const transaction = JSON.parse(formParams.signTransaction)
209       return signAndSubmitTransaction(transaction)
210     }
211
212   }
213 }
214
215 const decode = (data) => {
216   return (dispatch) => {
217     return  chainClient().transactions.decodeTransaction(data)
218       .then((resp) => {
219         if (resp.status === 'fail') {
220           dispatch({type: 'ERROR', payload: {'message': resp.msg}})
221         } else {
222           dispatch({type: 'DECODE_TRANSACTION', data:resp.data})
223         }
224       })
225       .catch(err => {
226         throw {_error: err}
227       })
228   }
229 }
230
231 export default {
232   ...list,
233   ...form,
234   decode,
235 }