Skip to content

Commit 778ad98

Browse files
author
mollkeith
committed
add manually confirm logic
1 parent 1f5f362 commit 778ad98

10 files changed

Lines changed: 335 additions & 19 deletions

File tree

app/arbiter/arbiter/arbiter.go

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"encoding/gob"
1010
"encoding/hex"
1111
"log"
12+
"math/big"
1213
"os"
1314
"path/filepath"
1415
"strings"
@@ -95,6 +96,7 @@ func NewArbiter(ctx context.Context, config *config.Config, password string) *Ar
9596
func (v *Arbiter) Start() {
9697
if v.config.Signer {
9798
go v.processArbiterSig()
99+
go v.processManualConfirm()
98100
}
99101

100102
if v.config.Listener {
@@ -113,6 +115,124 @@ func (v *Arbiter) listenESCContract() {
113115
v.escNode.Start(startHeight)
114116
}
115117

118+
func (v *Arbiter) processManualConfirm() {
119+
g.Log().Info(v.ctx, "process manually confirm start")
120+
121+
for {
122+
// get all deploy file
123+
files, err := os.ReadDir(v.config.LoanManuallyConfirmedPath)
124+
if err != nil {
125+
g.Log().Error(v.ctx, "read dir error", err)
126+
continue
127+
}
128+
129+
for _, file := range files {
130+
// read file
131+
filePath := v.config.LoanManuallyConfirmedPath + "/" + file.Name()
132+
fileContent, err := os.ReadFile(filePath)
133+
if err != nil {
134+
g.Log().Error(v.ctx, "read file error", err)
135+
continue
136+
}
137+
logEvt, err := v.decodeLogEvtByFileContent(fileContent)
138+
if err != nil {
139+
g.Log().Error(v.ctx, "decodeLogEvtByFileContent error", err)
140+
v.moveToDirectory(filePath, v.config.LoanNeedSignFailedPath+"/"+file.Name()+".mcFailed")
141+
v.logger.Println("[ERR] MCFM: decode event failed, file:", filePath)
142+
continue
143+
}
144+
var ev = make(map[string]interface{})
145+
err = v.escNode.Order_abi.UnpackIntoMap(ev, "ConfirmTransferToLenderEvent", logEvt.EventData)
146+
if err != nil {
147+
g.Log().Error(v.ctx, "UnpackIntoMap error", err)
148+
v.moveToDirectory(filePath, v.config.LoanNeedSignFailedPath+"/"+file.Name()+".mcFailed")
149+
v.logger.Println("[ERR] MCFM: unpack event into map failed, file:", filePath)
150+
continue
151+
}
152+
g.Log().Info(v.ctx, "ev", ev)
153+
orderId := logEvt.Topics[1]
154+
btcTxHash := logEvt.Topics[2]
155+
arbiterAddresss := common.BytesToAddress(logEvt.Topics[3][:])
156+
fee := ev["arbitratorBtcFee"].(*big.Int)
157+
158+
g.Log().Info(v.ctx, "orderId", hex.EncodeToString(orderId[:]))
159+
g.Log().Info(v.ctx, "btcTxHash", hex.EncodeToString(btcTxHash[:]))
160+
g.Log().Info(v.ctx, "arbiterAddresss", arbiterAddresss.String())
161+
162+
// get btc arbiter BTC address
163+
arbitratorBTCAddress, err := v.escNode.GetArbiterBTCAddress(arbiterAddresss)
164+
if err != nil {
165+
g.Log().Error(v.ctx, "GetArbiterOperatorAddress error", err)
166+
v.moveToDirectory(filePath, v.config.LoanNeedSignFailedPath+"/"+file.Name()+".mcGetArbiterOperatorAddressFailed")
167+
v.logger.Println("[ERR] MCFM: get arbiter operator address failed, block:", logEvt.Block, "tx:", logEvt.TxHash)
168+
continue
169+
}
170+
171+
btcTx, err := v.mempoolAPI.GetRawTransaction(hex.EncodeToString(btcTxHash[:]))
172+
if err != nil {
173+
g.Log().Error(v.ctx, "GetRawTransaction error", err)
174+
// v.moveToDirectory(filePath, v.config.LoanNeedSignFailedPath+"/"+file.Name()+".GetRawTransactionFailed")
175+
v.logger.Println("[ERR] MCFM: get raw tx failed, block:", logEvt.Block, "tx:", logEvt.TxHash)
176+
continue
177+
}
178+
// check if have enough fee
179+
realFee := int64(0)
180+
// feeOutputIndex := 0
181+
for _, vout := range btcTx.Vout {
182+
if vout.Value < 546 {
183+
g.Log().Error(v.ctx, "invalid tx outputs with dust value")
184+
v.moveToDirectory(filePath, v.config.LoanNeedSignFailedPath+"/"+file.Name()+".mcInvalidTxOutputs")
185+
v.logger.Println("[ERR] MCFM: invalid tx outputs with dust value, block:", logEvt.Block, "tx:", logEvt.TxHash)
186+
continue
187+
}
188+
utxoAddr := vout.ScriptpubkeyAddress
189+
if utxoAddr == arbitratorBTCAddress {
190+
g.Log().Error(v.ctx, "invalid utxo address:", utxoAddr, "need to be:", arbitratorBTCAddress)
191+
v.moveToDirectory(filePath, v.config.LoanNeedSignFailedPath+"/"+file.Name()+".mcInvalidUtxoAddress")
192+
v.logger.Println("[ERR] MCFM: invalid utxo address, block:", logEvt.Block, "tx:", logEvt.TxHash)
193+
continue
194+
}
195+
if vout.Value > 0 {
196+
realFee += vout.Value
197+
// feeOutputIndex = i
198+
break
199+
}
200+
}
201+
// check fee rate
202+
// preAmount := int64(btcTx.Vout[1-feeOutputIndex].Value)
203+
// feeRate, err := v.escNode.GetManuallyConfirmedBTCFeeRate(&arbiterAddresss)
204+
// if err != nil {
205+
// g.Log().Error(v.ctx, "GetManuallyConfirmedBTCFeeRate error", err)
206+
// v.moveToDirectory(filePath, v.config.LoanNeedSignFailedPath+"/"+file.Name()+".mcGetManuallyConfirmedBTCFeeRate")
207+
// v.logger.Println("[ERR] MCFM: get fee rate failed, block:", logEvt.Block, "tx:", logEvt.TxHash)
208+
// continue
209+
// }
210+
// arbiterFee := preAmount * feeRate.Int64() / 10000
211+
if realFee < fee.Int64() {
212+
g.Log().Error(v.ctx, "invalid fee:", realFee, "need to be:", fee.Int64())
213+
v.moveToDirectory(filePath, v.config.LoanNeedSignFailedPath+"/"+file.Name()+".mcInvalidFeeRate")
214+
v.logger.Println("[ERR] MCFM: invalid fee rate, block:", logEvt.Block, "tx:", logEvt.TxHash)
215+
continue
216+
}
217+
218+
// manually confirm to contract
219+
orderContarctAddress := common.BytesToAddress(orderId[:])
220+
txhash, err := v.escNode.SubmitManuallyConfirmed(&orderContarctAddress)
221+
g.Log().Notice(v.ctx, "SubmitManuallyConfirmed", "txhash ", txhash.String(), " error ", err)
222+
if err != nil {
223+
v.moveToDirectory(filePath, v.config.LoanNeedSignFailedPath+"/"+file.Name()+".mcSubmitSignatureFailed")
224+
v.logger.Println("[ERR] MCFM: SubmitManuallyConfirmed failed, block:", logEvt.Block, "tx:", logEvt.TxHash, "err:", err.Error())
225+
} else {
226+
v.moveToDirectory(filePath, v.config.LoanNeedSignSignedPath+"/"+file.Name()+".mcSucceed")
227+
v.logger.Println("[INF] MCFM: SubmitManuallyConfirmed succeed, block:", logEvt.Block, "tx:", logEvt.TxHash)
228+
}
229+
}
230+
231+
// sleep 10s to check and process next files
232+
time.Sleep(time.Second * 10)
233+
}
234+
}
235+
116236
func (v *Arbiter) processArbiterSig() {
117237
g.Log().Info(v.ctx, "processArbiterSignature start")
118238

@@ -387,6 +507,20 @@ func createDir(config *config.Config) error {
387507
}
388508
}
389509

510+
if !gfile.Exists(config.LoanSignedEventPath) {
511+
err := gfile.Mkdir(config.LoanSignedEventPath)
512+
if err != nil {
513+
return err
514+
}
515+
}
516+
517+
if !gfile.Exists(config.LoanManuallyConfirmedPath) {
518+
err := gfile.Mkdir(config.LoanManuallyConfirmedPath)
519+
if err != nil {
520+
return err
521+
}
522+
}
523+
390524
if !gfile.Exists(config.LoanLogPath) {
391525
err := gfile.Mkdir(config.LoanLogPath)
392526
if err != nil {

app/arbiter/config/config.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ type Config struct {
1313
ESCArbiterContractAddress string
1414
ESCArbiterManagerContractAddress string
1515
ESCConfigManagerContractAddress string
16+
ESCOrderManagerContractAddress string
1617
ESCArbiterAddress string
1718

1819
DataDir string
@@ -27,6 +28,8 @@ type Config struct {
2728
LoanNeedSignFailedPath string
2829
// loan signed path
2930
LoanNeedSignSignedPath string
31+
// loan manually confirmed path
32+
LoanManuallyConfirmedPath string
3033
// loan logs path
3134
LoanLogPath string
3235

app/arbiter/contract/contract_abi/arbiterManagerABI.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,32 @@
33
package contract_abi
44

55
const ArbiterManagerABI = `[
6+
{
7+
"inputs": [
8+
{
9+
"internalType": "address",
10+
"name": "arbitrator",
11+
"type": "address"
12+
}
13+
],
14+
"name": "getArbitratorInfoExt",
15+
"outputs": [
16+
{
17+
"components": [
18+
{
19+
"internalType": "uint256",
20+
"name": "currentBTCFeeRate",
21+
"type": "uint256"
22+
}
23+
],
24+
"internalType": "struct DataTypes.ArbitratorInfoExt",
25+
"name": "",
26+
"type": "tuple"
27+
}
28+
],
29+
"stateMutability": "view",
30+
"type": "function"
31+
},
632
{
733
"inputs": [],
834
"stateMutability": "nonpayable",
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright (c) 2025 The bel2 developers
2+
3+
package contract_abi
4+
5+
const OrderEventManagerABI = `[
6+
{
7+
"anonymous": false,
8+
"inputs": [
9+
{
10+
"indexed": true,
11+
"internalType": "address",
12+
"name": "order",
13+
"type": "address"
14+
},
15+
{
16+
"indexed": true,
17+
"internalType": "bytes32",
18+
"name": "txId",
19+
"type": "bytes32"
20+
},
21+
{
22+
"indexed": true,
23+
"internalType": "address",
24+
"name": "arbitrator",
25+
"type": "address"
26+
},
27+
{
28+
"indexed": false,
29+
"internalType": "uint32",
30+
"name": "txIndex",
31+
"type": "uint32"
32+
},
33+
{
34+
"indexed": false,
35+
"internalType": "uint256",
36+
"name": "arbitratorBtcFee",
37+
"type": "uint256"
38+
}
39+
],
40+
"name": "ConfirmTransferToLenderEvent",
41+
"type": "event"
42+
},
43+
{
44+
"inputs": [],
45+
"name": "confirmTransferToArbitrator",
46+
"outputs": [],
47+
"stateMutability": "nonpayable",
48+
"type": "function"
49+
}
50+
]`

app/arbiter/contract/contract_listener.go

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,22 @@ import (
1717

1818
type ContractListener struct {
1919
loanContract common.Address
20+
orderContract common.Address
21+
2022
queryClient *CrossClient
2123
listeneTopics []common.Hash
2224
ctx context.Context
2325
chan_events chan *events.ContractLogEvent
2426
}
2527

2628
func NewListener(ctx context.Context, client *CrossClient,
27-
loanContract common.Address, chan_event chan *events.ContractLogEvent) (*ContractListener, error) {
29+
loanContract, orderContract common.Address, chan_event chan *events.ContractLogEvent) (*ContractListener, error) {
2830
c := &ContractListener{
29-
queryClient: client,
30-
loanContract: loanContract,
31-
ctx: ctx,
32-
chan_events: chan_event,
31+
queryClient: client,
32+
loanContract: loanContract,
33+
orderContract: orderContract,
34+
ctx: ctx,
35+
chan_events: chan_event,
3336
}
3437
c.listeneTopics = make([]common.Hash, 0)
3538
return c, nil
@@ -48,7 +51,11 @@ func (c *ContractListener) Start(startHeight uint64) (uint64, error) {
4851

4952
distance := uint64(10000)
5053
toBlock := startHeight
51-
loanQuery := c.queryClient.BuildQuery(c.loanContract, c.listeneTopics, nil, nil)
54+
// addresses := []common.Address{c.orderContract}
55+
addresses := []common.Address{c.loanContract, c.orderContract}
56+
g.Log().Infof(c.ctx, "startHeight:%d, endBlock:%d, distance:%d", startHeight, endBlock, distance)
57+
g.Log().Infof(c.ctx, "loanContract:%s, orderContract:%s", c.loanContract.String(), c.orderContract.String())
58+
loanQuery := c.queryClient.BuildQuery(addresses, c.listeneTopics, nil, nil)
5259
for i := startHeight; i <= endBlock-confirmBlocksCount; i += distance {
5360
if i+distance < endBlock {
5461
toBlock = i + distance

0 commit comments

Comments
 (0)