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
9596func (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+
116236func (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 {
0 commit comments