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'
7 const type = 'transaction'
9 const list = baseListActions(type, {
12 const form = baseCreateActions(type)
14 function preprocessTransaction(formParams) {
15 const copy = JSON.parse(JSON.stringify(formParams))
17 baseTransaction: copy.baseTransaction,
18 actions: copy.actions || [],
21 if (formParams.form === 'normalTx') {
22 const gasPrice = formParams.state.estimateGas * Number(formParams.gasLevel)
24 builder.actions.push({
25 accountAlias: formParams.accountAlias,
26 accountId: formParams.accountId,
28 amount: Number(gasPrice),
31 builder.actions.push({
32 accountAlias: formParams.accountAlias,
33 accountId: formParams.accountId,
34 assetAlias: formParams.assetAlias,
35 assetId: formParams.assetId,
36 amount: formParams.amount,
39 builder.actions.push({
40 address: formParams.address,
41 assetAlias: formParams.assetAlias,
42 assetId: formParams.assetId,
43 amount: formParams.amount,
44 type: 'control_address'
48 if (builder.baseTransaction == '') {
49 delete builder.baseTransaction
52 if (formParams.submitAction == 'generate') {
53 builder.ttl = '1h' // 1 hour
56 for (let i in builder.actions) {
57 let a = builder.actions[i]
59 const intFields = ['amount', 'position']
60 intFields.forEach(key => {
63 if ((parseInt(value) + '') == value) {
64 a[key] = parseInt(value)
66 throw new Error(`Action ${parseInt(i) + 1} ${key} must be an integer.`)
72 a.referenceData = parseNonblankJSON(a.referenceData)
74 throw new Error(`Action ${parseInt(i) + 1} reference data should be valid JSON, or blank.`)
78 a.receiver = parseNonblankJSON(a.receiver)
80 throw new Error(`Action ${parseInt(i) + 1} receiver should be valid JSON.`)
87 form.submitForm = (formParams) => function (dispatch) {
88 const client = chainClient()
90 const builderFunction = ( builder ) => {
91 const processed = preprocessTransaction(formParams)
93 builder.actions = processed.actions
94 if (processed.baseTransaction) {
95 builder.baseTransaction = processed.baseTransaction
99 const submitSucceeded = () => {
100 dispatch(form.created())
102 pathname: '/transactions',
109 // normal transactions
110 if(formParams.form === 'normalTx'){
112 const accountId = formParams.accountId
113 const accountAlias = formParams.accountAlias
114 const accountInfo = Object.assign({}, accountAlias!== ''? {alias: accountAlias}: {id: accountId})
116 return client.accounts.query(accountInfo)
118 if(resp.data[0].xpubs.length > 1){
119 throw new Error('Your account has multiple keys, please use advanced transactions.')
121 const body = Object.assign({}, {xpub: resp.data[0].xpubs[0], password: formParams.password})
122 return client.mockHsm.keys.checkPassword(body)
125 if(!result.data.checkResult){
126 throw new Error('Your password is wrong, please check your password.')
128 return client.transactions.build(builderFunction)
131 const body = Object.assign({}, {password: formParams.password, transaction: tpl.data})
132 return client.transactions.sign(body)
135 if(!signed.data.signComplete){
136 throw new Error('Signature failed.')
138 return client.transactions.submit(signed.data.transaction.rawTransaction)
140 .then(submitSucceeded)
143 //advanced transactions
145 const buildPromise = (formParams.state.showAdvanced && formParams.signTransaction) ? null :
146 client.transactions.build(builderFunction)
148 if (formParams.submitAction == 'submit') {
149 const signAndSubmitTransaction = (transaction) => {
150 const body = Object.assign({}, {password: formParams.password, transaction: transaction})
151 return client.transactions.sign(body)
152 .then( signed => client.transactions.submit(signed.data.transaction.rawTransaction) )
153 .then(submitSucceeded)
156 if( formParams.state.showAdvanced
157 && formParams.signTransaction ){
158 const transaction = JSON.parse(formParams.signTransaction)
159 return signAndSubmitTransaction(transaction)
163 .then(tpl => signAndSubmitTransaction(tpl.data))
166 // submitAction == 'generate'
167 const signAndSubmitGeneratedTransaction = (transaction) => {
168 const body = Object.assign({}, {password: formParams.password, transaction: transaction})
169 return client.transactions.sign(body)
173 type: 'GENERATED_TX_HEX',
176 hex: JSON.stringify(resp.data.transaction),
179 dispatch(push(`/transactions/generated/${id}`))
183 if (formParams.state.showAdvanced
184 && formParams.signTransaction) {
185 const transaction = JSON.parse(formParams.signTransaction)
186 return signAndSubmitGeneratedTransaction(transaction)
190 .then(resp => signAndSubmitGeneratedTransaction(resp.data))
194 const decode = (data) => {
195 return (dispatch) => {
196 return chainClient().transactions.decodeTransaction(data)
198 if (resp.status === 'fail') {
199 dispatch({type: 'ERROR', payload: {'message': resp.msg}})
201 dispatch({type: 'DECODE_TRANSACTION', data:resp.data})