Skip to content

Commit 1dcf5e1

Browse files
committed
feat: split tx service to multi files
1 parent f78e1f4 commit 1dcf5e1

7 files changed

Lines changed: 694 additions & 8 deletions

File tree

packages/neuron-wallet/src/services/transactions.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { getConnection, In, ObjectLiteral } from 'typeorm'
2-
import { ReplaySubject } from 'rxjs'
32
import {
43
OutPoint,
54
Transaction,
@@ -73,8 +72,6 @@ export enum SearchType {
7372
/* eslint no-await-in-loop: "off" */
7473
/* eslint no-restricted-syntax: "off" */
7574
export default class TransactionsService {
76-
public static txSentSubject = new ReplaySubject<{ transaction: TransactionWithoutHash; txHash: string }>(100)
77-
7875
public static filterSearchType = (value: string) => {
7976
if (value === '') {
8077
return SearchType.Empty
@@ -680,8 +677,3 @@ export default class TransactionsService {
680677
return getConnection().manager.save(transactionEntity)
681678
}
682679
}
683-
684-
// listen to send tx event
685-
TransactionsService.txSentSubject.subscribe(msg => {
686-
TransactionsService.saveSentTx(msg.transaction, msg.txHash)
687-
})
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { getConnection, In } from 'typeorm'
2+
import { TransactionStatus } from '../../types/cell-types'
3+
import OutputEntity from '../../database/chain/entities/output'
4+
import TransactionEntity from '../../database/chain/entities/transaction'
5+
import { OutputStatus } from './params'
6+
import TransactionsService from './transaction-service'
7+
8+
export default class FailedTransaction {
9+
public static pendings = async (): Promise<TransactionEntity[]> => {
10+
const pendingTransactions = await getConnection()
11+
.getRepository(TransactionEntity)
12+
.createQueryBuilder('tx')
13+
.where({
14+
status: TransactionStatus.Pending,
15+
})
16+
.getMany()
17+
18+
return pendingTransactions
19+
}
20+
21+
// update tx status to TransactionStatus.Failed
22+
// update outputs status to OutputStatus.Failed
23+
// update previous outputs (inputs) to OutputStatus.Live
24+
public static updateFailedTxs = async (hashes: string[]) => {
25+
const txs = await getConnection()
26+
.getRepository(TransactionEntity)
27+
.createQueryBuilder('tx')
28+
.leftJoinAndSelect('tx.inputs', 'input')
29+
.leftJoinAndSelect('tx.outputs', 'output')
30+
.where({
31+
hash: In(hashes),
32+
status: TransactionStatus.Pending,
33+
})
34+
.getMany()
35+
36+
const txToUpdate = txs.map(tx => {
37+
const transaction = tx
38+
transaction.status = TransactionStatus.Failed
39+
return transaction
40+
})
41+
const allOutputs = txs
42+
.map(tx => tx.outputs)
43+
.reduce((acc, val) => acc.concat(val), [])
44+
.map(o => {
45+
const output = o
46+
output.status = OutputStatus.Failed
47+
return output
48+
})
49+
const allInputs = txs.map(tx => tx.inputs).reduce((acc, val) => acc.concat(val), [])
50+
const previousOutputs = await Promise.all(
51+
allInputs.map(async input => {
52+
const output = await getConnection()
53+
.getRepository(OutputEntity)
54+
.createQueryBuilder('output')
55+
.where({
56+
outPointTxHash: input.outPointTxHash,
57+
outPointIndex: input.outPointIndex,
58+
})
59+
.getOne()
60+
if (output) {
61+
output.status = OutputStatus.Live
62+
}
63+
return output
64+
})
65+
)
66+
const previous = previousOutputs.filter(output => output) as OutputEntity[]
67+
await getConnection().manager.save([...txToUpdate, ...allOutputs, ...previous])
68+
const blake160s = txs.map(tx => TransactionsService.blake160sOfTx(tx.toInterface()))
69+
const uniqueBlake160s = [...new Set(blake160s.reduce((acc, val) => acc.concat(val), []))]
70+
return uniqueBlake160s
71+
}
72+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { TransactionWithoutHash, Cell, ScriptHashType } from '../../types/cell-types'
2+
import CellsService, { MIN_CELL_CAPACITY } from '../cells'
3+
import LockUtils from '../../models/lock-utils'
4+
import { CapacityTooSmall } from '../../exceptions'
5+
import { TargetOutput } from './params'
6+
7+
export default class GenerateTransaction {
8+
// lockHashes for each inputs
9+
public static generateTx = async (
10+
lockHashes: string[],
11+
targetOutputs: TargetOutput[],
12+
changeAddress: string,
13+
fee: string = '0'
14+
): Promise<TransactionWithoutHash> => {
15+
const { codeHash, outPoint } = await LockUtils.systemScript()
16+
17+
const needCapacities: bigint = targetOutputs
18+
.map(o => BigInt(o.capacity))
19+
.reduce((result, c) => result + c, BigInt(0))
20+
21+
const minCellCapacity = BigInt(MIN_CELL_CAPACITY)
22+
23+
const outputs: Cell[] = targetOutputs.map(o => {
24+
const { capacity, address } = o
25+
26+
if (BigInt(capacity) < minCellCapacity) {
27+
throw new CapacityTooSmall()
28+
}
29+
30+
const blake160: string = LockUtils.addressToBlake160(address)
31+
32+
const output: Cell = {
33+
capacity,
34+
data: '0x',
35+
lock: {
36+
codeHash,
37+
args: [blake160],
38+
hashType: ScriptHashType.Data,
39+
},
40+
}
41+
42+
return output
43+
})
44+
45+
const { inputs, capacities } = await CellsService.gatherInputs(needCapacities.toString(), lockHashes, fee)
46+
47+
// change
48+
if (BigInt(capacities) > needCapacities + BigInt(fee)) {
49+
const changeBlake160: string = LockUtils.addressToBlake160(changeAddress)
50+
51+
const output: Cell = {
52+
capacity: `${BigInt(capacities) - needCapacities - BigInt(fee)}`,
53+
data: '0x',
54+
lock: {
55+
codeHash,
56+
args: [changeBlake160],
57+
hashType: ScriptHashType.Data,
58+
},
59+
}
60+
61+
outputs.push(output)
62+
}
63+
64+
return {
65+
version: '0',
66+
deps: [outPoint],
67+
inputs,
68+
outputs,
69+
witnesses: [],
70+
}
71+
}
72+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export * from './transaction-service'
2+
export * from './save-transaction'
3+
export * from './generate-transaction'
4+
export * from './failed-transaction'
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
export interface TargetOutput {
2+
address: string
3+
capacity: string
4+
}
5+
6+
export enum TxSaveType {
7+
Sent = 'sent',
8+
Fetch = 'fetch',
9+
}
10+
11+
export enum OutputStatus {
12+
Sent = 'sent',
13+
Live = 'live',
14+
Pending = 'pending',
15+
Dead = 'dead',
16+
Failed = 'failed',
17+
}

0 commit comments

Comments
 (0)