on 483c410 help sign in
bridge/src/lib/txn.js
160 lines 3.8 kB history raw
1import * as ob from 'urbit-ob'
2import Maybe from 'folktale/maybe'
3import Result from 'folktale/result'
4import Tx from 'ethereumjs-tx'
5import Web3 from 'web3'
7import { BRIDGE_ERROR } from '../lib/error'
8import { ledgerSignTransaction } from '../lib/ledger'
9import { trezorSignTransaction } from '../lib/trezor'
10import {
11 WALLET_NAMES,
12 addHexPrefix
13 } from '../lib/wallet'
15const TXN_PURPOSE = {
16 SET_MANAGEMENT_PROXY: Symbol('SET_MANAGEMENT_PROXY'),
17 SET_TRANSFER_PROXY: Symbol('SET_TRANSFER_PROXY'),
18 SET_SPAWN_PROXY: Symbol('SET_SPAWN_PROXY'),
19 CREATE_GALAXY: Symbol('CREATE_GALAXY'),
20 ISSUE_CHILD: Symbol('ISSUE_CHILD'),
21 SET_KEYS: Symbol('SET_KEYS'),
22 TRANSFER: Symbol('TRANSFER'),
23 CANCEL_TRANSFER: Symbol('CANCEL_TRANSFER')
26const renderTxnPurpose = (purpose) =>
27 purpose === TXN_PURPOSE.SET_MANAGEMENT_PROXY
28 ? 'set this management proxy'
29 : purpose === TXN_PURPOSE.SET_SPAWN_PROXY
30 ? 'set this spawn proxy'
31 : purpose === TXN_PURPOSE.SET_TRANSFER_PROXY
32 ? 'set this transfer proxy'
33 : purpose === TXN_PURPOSE.CREATE_GALAXY
34 ? 'create this galaxy'
35 : purpose === TXN_PURPOSE.ISSUE_CHILD
36 ? 'issue this point'
37 : purpose === TXN_PURPOSE.SET_KEYS
38 ? 'set these network keys'
39 : purpose === TXN_PURPOSE.TRANSFER
40 ? 'transfer this point'
41 : purpose === TXN_PURPOSE.CANCEL_TRANSFER
42 ? 'cancel this transfer'
43 : 'perform this transaction'
45const signTransaction = async config => {
47 let {
48 wallet,
49 walletType,
50 walletHdPath,
51 txn,
52 setStx,
53 nonce,
54 chainId,
55 gasPrice,
56 gasLimit
57 } = config
59 nonce = toHex(nonce)
60 chainId = toHex(chainId)
61 gasPrice = toHex(toWei(gasPrice, 'gwei'))
62 gasLimit = toHex(gasLimit)
64 const wal = wallet.matchWith({
65 Just: (w) => w.value,
66 Nothing: () => { throw BRIDGE_ERROR.MISSING_WALLET }
67 })
69 const sec = wal.privateKey
71 const utx = txn.matchWith({
72 Just: (tx) =>
73 Object.assign(tx.value, { nonce, chainId, gasPrice, gasLimit }),
74 Nothing: () => {
75 throw BRIDGE_ERROR.MISSING_TXN
76 }
77 })
79 const stx = new Tx(utx)
81 if (walletType === WALLET_NAMES.LEDGER) {
82 await ledgerSignTransaction(stx, walletHdPath)
83 } else if (walletType === WALLET_NAMES.TREZOR) {
84 await trezorSignTransaction(stx, walletHdPath)
85 } else {
86 stx.sign(sec)
87 }
89 setStx(Maybe.Just(stx))
92const sendSignedTransaction = (web3, stx) => {
93 const txn = stx.matchWith({
94 Just: (tx) => tx.value,
95 Nothing: () => {
96 throw BRIDGE_ERROR.MISSING_TXN
97 }
98 })
100 const serializedTx = addHexPrefix(txn.serialize().toString('hex'))
102 return new Promise((resolve, reject) => {
103 web3.eth.sendSignedTransaction(serializedTx)
104 .on('receipt', txn =>
105 resolve(Maybe.Just(Result.Ok(txn)))
106 )
107 .on('error', err => {
108 reject(Maybe.Just(Result.Error(err.message)))
109 })
110 })
113const hexify = val => addHexPrefix(val.toString('hex'))
115const renderSignedTx = stx => ({
116 messageHash: hexify(stx.hash()),
117 v: hexify(stx.v),
118 s: hexify(stx.s),
119 r: hexify(stx.r),
120 rawTransaction: hexify(stx.serialize())
121})
123const getTxnInfo = async (web3, addr) => {
124 let nonce = await web3.eth.getTransactionCount(addr)
125 let chainId = await web3.eth.net.getId()
126 let gasPrice = await web3.eth.getGasPrice()
127 return {
128 nonce: nonce,
129 chainId: chainId,
130 gasPrice: fromWei(gasPrice, 'gwei')
131 }
134const dummy = new Web3()
135const toHex = dummy.utils.toHex
136const toWei = dummy.utils.toWei
137const fromWei = dummy.utils.fromWei
139const canDecodePatp = p => {
140 try {
141 ob.patp2dec(p)
142 return true
143 } catch (_) {
144 return false
145 }
148export {
149 signTransaction,
150 sendSignedTransaction,
151 TXN_PURPOSE,
152 getTxnInfo,
153 renderTxnPurpose,
154 hexify,
155 renderSignedTx,
156 toHex,
157 toWei,
158 fromWei,
159 canDecodePatp,