@@ -30,10 +30,9 @@ import (
3030// CashChequeBeneficiaryTransactionCost is the expected gas cost of a CashChequeBeneficiary transaction
3131const CashChequeBeneficiaryTransactionCost = 50000
3232
33- // CashoutProcessor holds all relevant fields needed for processing cashouts
34- type CashoutProcessor struct {
35- backend chain.Backend // ethereum backend to use
36- privateKey * ecdsa.PrivateKey // private key to use
33+ var CashoutRequestTypeID = chain.TransactionRequestTypeID {
34+ Handler : "cashout" ,
35+ RequestType : "CashoutRequest" ,
3736}
3837
3938// CashoutRequest represents a request for a cashout operation
@@ -42,42 +41,106 @@ type CashoutRequest struct {
4241 Destination common.Address // destination for the payout
4342}
4443
45- // ActiveCashout stores the necessary information for a cashout in progess
46- type ActiveCashout struct {
47- Request CashoutRequest // the request that caused this cashout
48- TransactionHash common.Hash // the hash of the current transaction for this request
44+ // CashoutProcessor holds all relevant fields needed for processing cashouts
45+ type CashoutProcessor struct {
46+ backend chain.Backend // ethereum backend to use
47+ txScheduler chain.TxScheduler // transaction queue to use
48+ cashoutDone chan * CashoutRequest
4949}
5050
5151// newCashoutProcessor creates a new instance of CashoutProcessor
52- func newCashoutProcessor (backend chain.Backend , privateKey * ecdsa.PrivateKey ) * CashoutProcessor {
53- return & CashoutProcessor {
54- backend : backend ,
55- privateKey : privateKey ,
52+ func newCashoutProcessor (txScheduler chain. TxScheduler , backend chain.Backend , privateKey * ecdsa.PrivateKey ) * CashoutProcessor {
53+ c := & CashoutProcessor {
54+ backend : backend ,
55+ txScheduler : txScheduler ,
5656 }
57+
58+ txScheduler .SetHandlers (CashoutRequestTypeID , & chain.TransactionRequestHandlers {
59+ Send : func (id uint64 , backend chain.Backend , opts * bind.TransactOpts ) (common.Hash , error ) {
60+ var request CashoutRequest
61+ if err := c .txScheduler .GetRequest (id , & request ); err != nil {
62+ return common.Hash {}, err
63+ }
64+
65+ cheque := request .Cheque
66+
67+ otherSwap , err := contract .InstanceAt (cheque .Contract , backend )
68+ if err != nil {
69+ return common.Hash {}, err
70+ }
71+
72+ tx , err := otherSwap .CashChequeBeneficiaryStart (opts , request .Destination , cheque .CumulativePayout , cheque .Signature )
73+ if err != nil {
74+ return common.Hash {}, err
75+ }
76+ return tx .Hash (), nil
77+ },
78+ NotifyReceipt : func (id uint64 , notification * chain.TransactionReceiptNotification ) error {
79+ var request * CashoutRequest
80+ err := c .txScheduler .GetRequest (id , & request )
81+ if err != nil {
82+ return err
83+ }
84+
85+ otherSwap , err := contract .InstanceAt (request .Cheque .Contract , c .backend )
86+ if err != nil {
87+ return err
88+ }
89+
90+ receipt := & notification .Receipt
91+ if receipt .Status == 0 {
92+ swapLog .Error ("cheque cashing transaction reverted" , "tx" , receipt .TxHash )
93+ return nil
94+ }
95+
96+ result := otherSwap .CashChequeBeneficiaryResult (receipt )
97+
98+ metrics .GetOrRegisterCounter ("swap.cheques.cashed.honey" , nil ).Inc (result .TotalPayout .Int64 ())
99+
100+ if result .Bounced {
101+ metrics .GetOrRegisterCounter ("swap.cheques.cashed.bounced" , nil ).Inc (1 )
102+ swapLog .Warn ("cheque bounced" , "tx" , receipt .TxHash )
103+ }
104+
105+ swapLog .Info ("cheque cashed" , "honey" , request .Cheque .Honey )
106+
107+ select {
108+ case c .cashoutDone <- request :
109+ default :
110+ }
111+
112+ return nil
113+ },
114+ })
115+ return c
57116}
58117
59- // cashCheque tries to cash the cheque specified in the request
60- // after the transaction is sent it waits on its success
61- func (c * CashoutProcessor ) cashCheque (ctx context.Context , request * CashoutRequest ) error {
62- cheque := request .Cheque
63- opts := bind .NewKeyedTransactor (c .privateKey )
64- opts .Context = ctx
118+ func (c * CashoutProcessor ) setCashoutDoneChan (cashoutDone chan * CashoutRequest ) {
119+ c .cashoutDone = cashoutDone
120+ }
65121
66- otherSwap , err := contract .InstanceAt (cheque .Contract , c .backend )
122+ func (c * CashoutProcessor ) submitCheque (request * CashoutRequest ) {
123+ expectedPayout , transactionCosts , err := c .estimatePayout (context .TODO (), & request .Cheque )
67124 if err != nil {
68- return err
125+ swapLog .Error ("could not estimate payout" , "error" , err )
126+ return
69127 }
70128
71- tx , err := otherSwap .CashChequeBeneficiaryStart (opts , request .Destination , cheque .CumulativePayout , cheque .Signature )
129+ costsMultiplier := uint256 .FromUint64 (2 )
130+ costThreshold , err := uint256 .New ().Mul (transactionCosts , costsMultiplier )
72131 if err != nil {
73- return err
132+ swapLog .Error ("overflow in transaction fee" , "error" , err )
133+ return
74134 }
75135
76- // this blocks until the cashout has been successfully processed
77- return c .waitForAndProcessActiveCashout (& ActiveCashout {
78- Request : * request ,
79- TransactionHash : tx .Hash (),
80- })
136+ // do a payout transaction if we get 2 times the gas costs
137+ if expectedPayout .Cmp (costThreshold ) == 1 {
138+ _ , err := c .txScheduler .ScheduleRequest (CashoutRequestTypeID , request )
139+ if err != nil {
140+ metrics .GetOrRegisterCounter ("swap.cheques.cashed.errors" , nil ).Inc (1 )
141+ swapLog .Error ("cashing cheque:" , "error" , err )
142+ }
143+ }
81144}
82145
83146// estimatePayout estimates the payout for a given cheque as well as the transaction cost
@@ -123,31 +186,3 @@ func (c *CashoutProcessor) estimatePayout(ctx context.Context, cheque *Cheque) (
123186
124187 return expectedPayout , transactionCosts , nil
125188}
126-
127- // waitForAndProcessActiveCashout waits for activeCashout to complete
128- func (c * CashoutProcessor ) waitForAndProcessActiveCashout (activeCashout * ActiveCashout ) error {
129- ctx , cancel := context .WithTimeout (context .Background (), DefaultTransactionTimeout )
130- defer cancel ()
131-
132- receipt , err := chain .WaitMined (ctx , c .backend , activeCashout .TransactionHash )
133- if err != nil {
134- return err
135- }
136-
137- otherSwap , err := contract .InstanceAt (activeCashout .Request .Cheque .Contract , c .backend )
138- if err != nil {
139- return err
140- }
141-
142- result := otherSwap .CashChequeBeneficiaryResult (receipt )
143-
144- metrics .GetOrRegisterCounter ("swap.cheques.cashed.honey" , nil ).Inc (result .TotalPayout .Int64 ())
145-
146- if result .Bounced {
147- metrics .GetOrRegisterCounter ("swap.cheques.cashed.bounced" , nil ).Inc (1 )
148- swapLog .Warn ("cheque bounced" , "tx" , receipt .TxHash )
149- }
150-
151- swapLog .Info ("cheque cashed" , "honey" , activeCashout .Request .Cheque .Honey )
152- return nil
153- }
0 commit comments