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 const normalT = formParams.normalTransaction
22 if (builder.actions.length == 0) {
23 builder.actions.push({
24 accountAlias: normalT.accountAlias,
25 accountId: normalT.accountId,
27 amount: Number(normalT.gas.price),
30 builder.actions.push({
31 accountAlias: normalT.accountAlias,
32 accountId: normalT.accountId,
33 assetAlias: normalT.assetAlias,
34 assetId: normalT.assetId,
35 amount: normalT.amount,
38 builder.actions.push({
39 address: normalT.address,
40 assetAlias: normalT.assetAlias,
41 assetId: normalT.assetId,
42 amount: normalT.amount,
43 type: 'control_address'
47 if (builder.baseTransaction == '') {
48 delete builder.baseTransaction
51 if (formParams.submitAction == 'generate') {
52 builder.ttl = '1h' // 1 hour
55 for (let i in builder.actions) {
56 let a = builder.actions[i]
58 const intFields = ['amount', 'position']
59 intFields.forEach(key => {
62 if ((parseInt(value) + '') == value) {
63 a[key] = parseInt(value)
65 throw new Error(`Action ${parseInt(i) + 1} ${key} must be an integer.`)
71 a.referenceData = parseNonblankJSON(a.referenceData)
73 throw new Error(`Action ${parseInt(i) + 1} reference data should be valid JSON, or blank.`)
77 a.receiver = parseNonblankJSON(a.receiver)
79 throw new Error(`Action ${parseInt(i) + 1} receiver should be valid JSON.`)
86 form.submitForm = (formParams) => function (dispatch) {
87 const buildPromise = chainClient().transactions.build(builder => {
88 const processed = preprocessTransaction(formParams)
90 builder.actions = processed.actions.map(action => {
92 address: action.address,
93 amount: action.amount,
94 account_id: action.accountId,
95 account_alias: action.accountAlias,
96 asset_id: action.assetId,
97 asset_alias: action.assetAlias,
100 if (action.receiver) {
102 control_program: action.receiver.controlProgram,
103 expires_at: action.receiver.expiresAt
108 if (processed.baseTransaction) {
109 builder.baseTransaction = processed.baseTransaction
113 const signAndSubmitTransaction = (transaction, password) => {
114 const connection = chainClient().connection
115 return connection.request('/sign-transaction', {
118 }, true).then(resp => {
119 if (resp.status === 'fail') {
120 throw new Error(resp.msg)
123 const raw_transaction = resp.data.transaction.raw_transaction
124 return connection.request('/submit-transaction', {raw_transaction})
125 }).then(dealSignSubmitResp)
128 const dealSignSubmitResp = resp => {
129 if (resp.status === 'fail') {
130 throw new Error(resp.msg)
133 dispatch(form.created())
135 pathname: '/transactions',
142 if (formParams.state.showAdvanceTx && formParams.state.showAdvanced && formParams.baseTransaction) {
143 const transaction = JSON.parse(formParams.baseTransaction)
144 return signAndSubmitTransaction(transaction, formParams.password)
147 if (formParams.submitAction == 'submit') {
150 if (resp.status === 'fail') {
151 throw new Error(resp.msg)
154 return signAndSubmitTransaction(resp.data, formParams.password)
158 // submitAction == 'generate'
159 return buildPromise.then(resp => {
160 if (resp.status === 'fail') {
161 throw new Error(resp.msg)
164 const body = Object.assign({}, {password: formParams.password, 'transaction': resp.data})
165 return chainClient().connection.request('/sign-transaction', body, true)
167 if (resp.status === 'fail') {
168 throw new Error(resp.msg)
172 type: 'GENERATED_TX_HEX',
175 hex: JSON.stringify(resp.data.transaction),
178 dispatch(push(`/transactions/generated/${id}`))